Skip to content

Commit ebb3ea4

Browse files
peterschrammeltautschnig
authored andcommitted
Typecheck friend type declarations
This does not yet include typechecking of friend methods. Includes a fix to permit rvalue conversion to const references, which ensures unambiguous resolution for member functions.
1 parent 311c98a commit ebb3ea4

File tree

18 files changed

+83
-82
lines changed

18 files changed

+83
-82
lines changed

regression/systemc/BitvectorSc1/main.cpp

+2-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
#include <cassert>
2-
31
template <int W>
42
class sc_uint {
53
public:
@@ -41,8 +39,8 @@ int main(int argc, char** argv)
4139
x.test1();
4240
x.test2();
4341

44-
assert(x.to_uint() == 1);
45-
assert(x.to_uint() == 2);
42+
__CPROVER_assert(x.to_uint() == 1, "");
43+
__CPROVER_assert(x.to_uint() == 2, "");
4644

4745
return 0;
4846
}

regression/systemc/BitvectorSc2/main.cpp

+1-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
#include <cassert>
2-
31
template <int W>
42
class sc_uint {
53
public:
@@ -56,7 +54,7 @@ int main(int argc, char** argv)
5654
z += y;
5755

5856
sc_uint<10> w(3);
59-
assert(z == w);
57+
__CPROVER_assert(z == w, "");
6058

6159
return 0;
6260
}

regression/systemc/BitvectorSc3/test.desc

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
KNOWNBUG
1+
CORE
22
main.cpp
33

44
^EXIT=0$

regression/systemc/EqualOp1/main.cpp

+1-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
#include <cassert>
2-
31
template<class T>
42
class myclass
53
{
@@ -20,5 +18,5 @@ int main(int argc, char** argv)
2018
myclass<int> x(0);
2119
myclass<int> y(1);
2220
x = y;
23-
assert(x == y);
21+
__CPROVER_assert(x == y, "");
2422
}

regression/systemc/EqualOp2/main.cpp

+1-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
#include <cassert>
2-
31
template<class T>
42
class myclass
53
{
@@ -26,5 +24,5 @@ int main(int argc, char** argv)
2624
myclass<int> y(1);
2725
//x = y;
2826
x += 1;
29-
assert(x == y);
27+
__CPROVER_assert(x == y, "");
3028
}

regression/systemc/EqualOp3/main.cpp

+1-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
#include <cassert>
2-
31
template<class T>
42
class myclass2;
53

@@ -38,6 +36,6 @@ int main(int argc, char** argv)
3836
myclass2<int> x(0);
3937
myclass<int> y(1);
4038
x = y;
41-
assert(x == y);
39+
__CPROVER_assert(x == y, "");
4240
return 0;
4341
}

regression/systemc/ForwardDecl1/test.desc

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
KNOWNBUG
1+
CORE
22
main.cpp
33

44
^EXIT=0$

regression/systemc/FunTempl1/main.cpp

+1-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
#include <cassert>
2-
31
template<class T>
42
T inc(T x)
53
{
@@ -15,5 +13,5 @@ int main(int argc, char** argv)
1513
x = inc<int>(x);
1614
y = inc<unsigned char>(y);
1715

18-
assert(x == y);
16+
__CPROVER_assert(x == y, "");
1917
}

regression/systemc/Mult1/test.desc

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
KNOWNBUG
22
main.cpp
3-
3+
--object-bits 10
44
^EXIT=0$
55
^SIGNAL=0$
66
^VERIFICATION SUCCESSFUL$

regression/systemc/SimpleSc1/main.cpp

+1-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
#include <cassert>
2-
31
template <int W>
42
class sc_uint {
53
public:
@@ -54,7 +52,7 @@ int main(int argc, char** argv)
5452
z += y;
5553

5654
sc_uint<10> w(3);
57-
assert(z == w);
55+
__CPROVER_assert(z == w, "");
5856

5957
return 0;
6058
}

regression/systemc/Template1/main.cpp

+2-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
#include <cassert>
2-
31
#define DEF_INSIDE
42

53
template<class T>
@@ -35,8 +33,8 @@ int main (int argc, char *argv[])
3533
my_template<int> x;
3634
x.set(5);
3735
int y = x.get();
38-
assert(y==5);
39-
assert(z.get()==3);
36+
__CPROVER_assert(y == 5, "");
37+
__CPROVER_assert(z.get() == 3, "");
4038

4139
return 0;
4240
}

regression/systemc/Tuple1/test.desc

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
KNOWNBUG
1+
CORE
22
main.cpp
33
-DNO_IO -DNO_STRING
44
^EXIT=0$

regression/systemc/Tuple2/test.desc

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
KNOWNBUG
1+
CORE
22
main.cpp
33
-DNO_IO -DNO_STRING
44
^EXIT=0$

src/cpp/cpp_declarator_converter.cpp

+24-7
Original file line numberDiff line numberDiff line change
@@ -64,11 +64,22 @@ symbolt &cpp_declarator_convertert::convert(
6464
cpp_typecheck_resolve.resolve_scope(
6565
declarator.name(), base_name, template_args);
6666

67+
cpp_scopet *friend_scope = nullptr;
68+
69+
if(is_friend)
70+
{
71+
friend_scope = &cpp_typecheck.cpp_scopes.current_scope();
72+
save_scope.restore();
73+
}
74+
6775
scope=&cpp_typecheck.cpp_scopes.current_scope();
6876

69-
// check the declarator-part of the type, in that scope
77+
// check the declarator-part of the type, in the current scope
7078
if(declarator.value().is_nil() || !cpp_typecheck.has_auto(final_type))
7179
cpp_typecheck.typecheck_type(final_type);
80+
81+
if(friend_scope)
82+
scope = friend_scope;
7283
}
7384

7485
is_code=is_code_type(final_type);
@@ -80,9 +91,9 @@ symbolt &cpp_declarator_convertert::convert(
8091
get_final_identifier();
8192

8293
// first see if it is a member
83-
if(scope->id_class==cpp_idt::id_classt::CLASS && !is_friend)
94+
if(scope->id_class == cpp_idt::id_classt::CLASS)
8495
{
85-
// it's a member! it must be declared already
96+
// it's a member! it must be declared already, unless it's a friend
8697

8798
typet &method_qualifier=
8899
static_cast<typet &>(declarator.method_qualifier());
@@ -118,7 +129,15 @@ symbolt &cpp_declarator_convertert::convert(
118129

119130
// try again
120131
maybe_symbol=cpp_typecheck.symbol_table.get_writeable(final_identifier);
121-
if(!maybe_symbol)
132+
if(!maybe_symbol && is_friend)
133+
{
134+
symbolt &friend_symbol =
135+
convert_new_symbol(storage_spec, member_spec, declarator);
136+
// mark it as weak so that the full declaration can replace the symbol
137+
friend_symbol.is_weak = true;
138+
return friend_symbol;
139+
}
140+
else if(!maybe_symbol)
122141
{
123142
cpp_typecheck.error().source_location=
124143
declarator.name().source_location();
@@ -411,9 +430,7 @@ void cpp_declarator_convertert::get_final_identifier()
411430
}
412431
}
413432

414-
final_identifier=
415-
scope->prefix+
416-
identifier;
433+
final_identifier = scope->prefix + identifier;
417434
}
418435

419436
symbolt &cpp_declarator_convertert::convert_new_symbol(

src/cpp/cpp_scopes.cpp

-1
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,6 @@ cpp_idt &cpp_scopest::put_into_scope(
4848
{
4949
cpp_save_scopet saved_scope(*this);
5050
go_to(scope);
51-
go_to_global_scope();
5251

5352
cpp_idt &id=current_scope().insert(symbol.base_name);
5453
id.identifier=symbol.name;

src/cpp/cpp_typecheck_compound_type.cpp

+30-38
Original file line numberDiff line numberDiff line change
@@ -861,13 +861,9 @@ void cpp_typecheckt::typecheck_friend_declaration(
861861

862862
if(declaration.is_template())
863863
{
864-
return; // TODO
865-
866-
#if 0
867864
error().source_location=declaration.type().source_location();
868865
error() << "friend template not supported" << eom;
869866
throw 0;
870-
#endif
871867
}
872868

873869
// we distinguish these whether there is a declarator
@@ -890,51 +886,41 @@ void cpp_typecheckt::typecheck_friend_declaration(
890886
throw 0;
891887
}
892888

893-
// typecheck ftype
894-
895-
// TODO
896-
// typecheck_type(ftype);
897-
// symbol.type.add("ID_C_friends").move_to_sub(ftype);
889+
cpp_save_scopet saved_scope(cpp_scopes);
890+
cpp_scopes.go_to_global_scope();
891+
typecheck_type(ftype);
892+
symbol.type.add(ID_C_friends).move_to_sub(ftype);
898893

899894
return;
900895
}
901896

902897
// It should be a friend function.
903898
// Do the declarators.
904899

900+
#ifdef DEBUG
901+
std::cout << "friend declaration: " << declaration.pretty() << '\n';
902+
#endif
903+
905904
for(auto &sub_it : declaration.declarators())
906905
{
907-
bool has_value = sub_it.value().is_not_nil();
908-
909-
if(!has_value)
910-
{
911-
// If no value is found, then we jump to the
912-
// global scope, and we convert the declarator
913-
// as if it were declared there
914-
cpp_save_scopet saved_scope(cpp_scopes);
915-
cpp_scopes.go_to_global_scope();
916-
cpp_declarator_convertert cpp_declarator_converter(*this);
917-
const symbolt &conv_symb=cpp_declarator_converter.convert(
918-
declaration.type(), declaration.storage_spec(),
919-
declaration.member_spec(), sub_it);
920-
exprt symb_expr=cpp_symbol_expr(conv_symb);
921-
symbol.type.add(ID_C_friends).move_to_sub(symb_expr);
922-
}
923-
else
924-
{
925-
cpp_declarator_convertert cpp_declarator_converter(*this);
926-
cpp_declarator_converter.is_friend=true;
906+
#ifdef DEBUG
907+
std::cout << "decl: " << sub_it.pretty() << "\n with value "
908+
<< sub_it.value().pretty() << '\n';
909+
std::cout << " scope: " << cpp_scopes.current_scope().prefix << '\n';
910+
#endif
927911

912+
if(sub_it.value().is_not_nil())
928913
declaration.member_spec().set_inline(true);
929914

930-
const symbolt &conv_symb=cpp_declarator_converter.convert(
931-
declaration.type(), declaration.storage_spec(),
932-
declaration.member_spec(), sub_it);
933-
934-
exprt symb_expr=cpp_symbol_expr(conv_symb);
935-
936-
symbol.type.add(ID_C_friends).move_to_sub(symb_expr);
937-
}
915+
cpp_declarator_convertert cpp_declarator_converter(*this);
916+
cpp_declarator_converter.is_friend = true;
917+
const symbolt &conv_symb = cpp_declarator_converter.convert(
918+
declaration.type(),
919+
declaration.storage_spec(),
920+
declaration.member_spec(),
921+
sub_it);
922+
exprt symb_expr = cpp_symbol_expr(conv_symb);
923+
symbol.type.add(ID_C_friends).move_to_sub(symb_expr);
938924
}
939925
}
940926

@@ -1322,7 +1308,13 @@ void cpp_typecheckt::typecheck_member_function(
13221308
// move early, it must be visible before doing any value
13231309
symbolt *new_symbol;
13241310

1325-
if(symbol_table.move(symbol, new_symbol))
1311+
const bool symbol_exists = symbol_table.move(symbol, new_symbol);
1312+
if(symbol_exists && new_symbol->is_weak)
1313+
{
1314+
// there might have been an earlier friend declaration
1315+
*new_symbol = std::move(symbol);
1316+
}
1317+
else if(symbol_exists)
13261318
{
13271319
error().source_location=symbol.location;
13281320
error() << "failed to insert new method symbol: " << symbol.name << '\n'

src/cpp/cpp_typecheck_conversions.cpp

+12-1
Original file line numberDiff line numberDiff line change
@@ -1251,10 +1251,21 @@ bool cpp_typecheckt::reference_binding(
12511251
return false;
12521252
}
12531253

1254-
if(expr.get_bool(ID_C_lvalue))
1254+
if(expr.get_bool(ID_C_lvalue) || type.subtype().get_bool(ID_C_constant))
12551255
{
12561256
if(reference_compatible(expr, type, rank))
12571257
{
1258+
if(!expr.get_bool(ID_C_lvalue))
1259+
{
1260+
// create temporary object
1261+
side_effect_exprt tmp{ID_temporary_object,
1262+
{std::move(expr)},
1263+
type.subtype(),
1264+
expr.source_location()};
1265+
tmp.set(ID_mode, ID_cpp);
1266+
expr.swap(tmp);
1267+
}
1268+
12581269
{
12591270
address_of_exprt tmp(expr, reference_type(expr.type()));
12601271
tmp.add_source_location()=expr.source_location();

src/cpp/cpp_typecheck_expr.cpp

+2-4
Original file line numberDiff line numberDiff line change
@@ -1175,11 +1175,9 @@ void cpp_typecheckt::typecheck_expr_member(
11751175
if(pcomp.is_nil())
11761176
{
11771177
error().source_location=expr.find_source_location();
1178-
error() << "error: `"
1179-
<< symbol_expr.get(ID_identifier)
1178+
error() << "error: `" << symbol_expr.get(ID_identifier)
11801179
<< "' is not static member "
1181-
<< "of class `" << to_string(type) << "'"
1182-
<< eom;
1180+
<< "of class `" << to_string(op0.type()) << "'" << eom;
11831181
throw 0;
11841182
}
11851183
}

0 commit comments

Comments
 (0)