Skip to content

Commit bf53cd8

Browse files
committed
C++ front-end: support explicit type conversion with braced-init-list
Now follows the grammar described in the C++ standard: Explicit type conversions are postfix expressions. This required adding rules for C++ cast expressions, which in turn simplifies type checking for we no longer treat them as function calls with template arguments.
1 parent 2e6200a commit bf53cd8

File tree

10 files changed

+341
-190
lines changed

10 files changed

+341
-190
lines changed
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#include <cassert>
2+
3+
int main(int argc, char *argv[])
4+
{
5+
struct S
6+
{
7+
S() : x(42)
8+
{
9+
}
10+
11+
int x;
12+
};
13+
S s = S{};
14+
15+
__CPROVER_assert(s.x == 42, "");
16+
assert(s.x == 42);
17+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
CORE
2+
main.cpp
3+
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^VERIFICATION SUCCESSFUL$
7+
--
8+
^warning: ignoring
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
struct __invoke_memfun_ref
2+
{
3+
};
4+
constexpr bool __call_is_nt(__invoke_memfun_ref)
5+
{
6+
return false;
7+
}
8+
9+
template <typename _Result>
10+
struct __call_is_nothrow
11+
{
12+
constexpr static bool is_nt = __call_is_nt(typename _Result::__invoke_type{});
13+
};
14+
15+
int main(int argc, char *argv[])
16+
{
17+
struct S
18+
{
19+
S() : x(42)
20+
{
21+
}
22+
23+
int x;
24+
};
25+
S s = S{};
26+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
CORE
2+
main.cpp
3+
-std=c++11
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
--
7+
^warning: ignoring
8+
^CONVERSION ERROR$

src/ansi-c/parser.y

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,10 @@ int yyansi_cerror(const std::string &error);
281281
%token TOK_MSC_IF_EXISTS "__if_exists"
282282
%token TOK_MSC_IF_NOT_EXISTS "__if_not_exists"
283283
%token TOK_UNDERLYING_TYPE "__underlying_type"
284+
%token TOK_DYNAMIC_CAST "dynamic_cast"
285+
%token TOK_STATIC_CAST "static_cast"
286+
%token TOK_REINTERPRET_CAST "reinterpret_cast"
287+
%token TOK_CONST_CAST "const_cast"
284288

285289
/*** priority, associativity, etc. definitions **************************/
286290

src/ansi-c/scanner.l

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1254,6 +1254,11 @@ enable_or_disable ("enable"|"disable")
12541254
TOK_BIT_CAST);
12551255
}
12561256

1257+
"dynamic_cast" { return conditional_keyword(PARSER.cpp98, TOK_DYNAMIC_CAST); }
1258+
"static_cast" { return conditional_keyword(PARSER.cpp98, TOK_STATIC_CAST); }
1259+
"reinterpret_cast" { return conditional_keyword(PARSER.cpp98, TOK_REINTERPRET_CAST); }
1260+
"const_cast" { return conditional_keyword(PARSER.cpp98, TOK_CONST_CAST); }
1261+
12571262
{CPROVER_PREFIX}"atomic" { loc(); return TOK_CPROVER_ATOMIC; }
12581263
{CPROVER_PREFIX}"forall" { loc(); return TOK_FORALL; }
12591264
{CPROVER_PREFIX}"exists" { loc(); return TOK_EXISTS; }

src/cpp/cpp_is_pod.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,10 @@ bool cpp_typecheckt::cpp_is_pod(const typet &type) const
7373
{
7474
return cpp_is_pod(to_array_type(type).element_type());
7575
}
76+
else if(type.id() == ID_vector)
77+
{
78+
return cpp_is_pod(to_vector_type(type).element_type());
79+
}
7680
else if(type.id()==ID_pointer)
7781
{
7882
if(is_reference(type)) // references are not PODs

src/cpp/cpp_typecheck_expr.cpp

Lines changed: 11 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,12 @@ void cpp_typecheckt::typecheck_expr_main(exprt &expr)
126126
{
127127
expr.type().id(ID_initializer_list);
128128
}
129+
else if(
130+
expr.id() == ID_const_cast || expr.id() == ID_dynamic_cast ||
131+
expr.id() == ID_reinterpret_cast || expr.id() == ID_static_cast)
132+
{
133+
typecheck_cast_expr(expr);
134+
}
129135
else
130136
c_typecheck_baset::typecheck_expr_main(expr);
131137
}
@@ -966,13 +972,8 @@ void cpp_typecheckt::typecheck_expr_explicit_constructor_call(exprt &expr)
966972
}
967973
else
968974
{
969-
CHECK_RETURN(expr.type().id() == ID_struct);
970-
971-
struct_tag_typet tag(expr.type().get(ID_name));
972-
tag.add_source_location() = expr.source_location();
973-
974975
exprt e=expr;
975-
new_temporary(e.source_location(), tag, e.operands(), expr);
976+
new_temporary(e.source_location(), e.type(), e.operands(), expr);
976977
}
977978
}
978979

@@ -1274,53 +1275,20 @@ void cpp_typecheckt::typecheck_expr_ptrmember(
12741275

12751276
void cpp_typecheckt::typecheck_cast_expr(exprt &expr)
12761277
{
1277-
side_effect_expr_function_callt e =
1278-
to_side_effect_expr_function_call(expr);
1279-
1280-
if(e.arguments().size() != 1)
1278+
if(expr.operands().size() != 1)
12811279
{
12821280
error().source_location=expr.find_source_location();
12831281
error() << "cast expressions expect one operand" << eom;
12841282
throw 0;
12851283
}
12861284

1287-
exprt &f_op=e.function();
1288-
exprt &cast_op=e.arguments().front();
1285+
exprt &cast_op = to_unary_expr(expr).op();
12891286

12901287
add_implicit_dereference(cast_op);
12911288

1292-
const irep_idt &id=
1293-
f_op.get_sub().front().get(ID_identifier);
1294-
1295-
if(f_op.get_sub().size()!=2 ||
1296-
f_op.get_sub()[1].id()!=ID_template_args)
1297-
{
1298-
error().source_location=expr.find_source_location();
1299-
error() << id << " expects template argument" << eom;
1300-
throw 0;
1301-
}
1302-
1303-
irept &template_arguments=f_op.get_sub()[1].add(ID_arguments);
1304-
1305-
if(template_arguments.get_sub().size()!=1)
1306-
{
1307-
error().source_location=expr.find_source_location();
1308-
error() << id << " expects one template argument" << eom;
1309-
throw 0;
1310-
}
1311-
1312-
irept &template_arg=template_arguments.get_sub().front();
1313-
1314-
if(template_arg.id() != ID_type && template_arg.id() != ID_ambiguous)
1315-
{
1316-
error().source_location=expr.find_source_location();
1317-
error() << id << " expects a type as template argument" << eom;
1318-
throw 0;
1319-
}
1320-
1321-
typet &type=static_cast<typet &>(
1322-
template_arguments.get_sub().front().add(ID_type));
1289+
const irep_idt &id = expr.id();
13231290

1291+
typet &type = expr.type();
13241292
typecheck_type(type);
13251293

13261294
source_locationt source_location=expr.source_location();
@@ -1414,21 +1382,6 @@ void cpp_typecheckt::typecheck_expr_cpp_name(
14141382
}
14151383
}
14161384

1417-
if(expr.get_sub().size()>=1 &&
1418-
expr.get_sub().front().id()==ID_name)
1419-
{
1420-
const irep_idt &id=expr.get_sub().front().get(ID_identifier);
1421-
1422-
if(id==ID_const_cast ||
1423-
id==ID_dynamic_cast ||
1424-
id==ID_reinterpret_cast ||
1425-
id==ID_static_cast)
1426-
{
1427-
expr.id(ID_cast_expression);
1428-
return;
1429-
}
1430-
}
1431-
14321385
exprt symbol_expr=
14331386
resolve(
14341387
to_cpp_name(expr),
@@ -1555,14 +1508,6 @@ void cpp_typecheckt::typecheck_side_effect_function_call(
15551508

15561509
return;
15571510
}
1558-
else if(expr.function().id() == ID_cast_expression)
1559-
{
1560-
// These are not really function calls,
1561-
// but usually just type adjustments.
1562-
typecheck_cast_expr(expr);
1563-
add_implicit_dereference(expr);
1564-
return;
1565-
}
15661511
else if(expr.function().id() == ID_cpp_dummy_destructor)
15671512
{
15681513
// these don't do anything, e.g., (char*)->~char()

0 commit comments

Comments
 (0)