Skip to content

Commit 5c1ace0

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.
1 parent 3882560 commit 5c1ace0

File tree

6 files changed

+151
-74
lines changed

6 files changed

+151
-74
lines changed
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#include <cassert>
2+
3+
int main(int argc, char * argv[])
4+
{
5+
struct S {
6+
S() : x(42)
7+
{
8+
}
9+
10+
int x;
11+
};
12+
S s = S{};
13+
14+
__CPROVER_assert(s.x == 42, "");
15+
assert(s.x == 42);
16+
}
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: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
struct __invoke_memfun_ref {};
2+
constexpr bool __call_is_nt(__invoke_memfun_ref)
3+
{
4+
return false;
5+
}
6+
7+
template<typename _Result>
8+
struct __call_is_nothrow
9+
{
10+
constexpr static bool is_nt =
11+
__call_is_nt(typename _Result::__invoke_type{});
12+
};
13+
14+
int main(int argc, char * argv[])
15+
{
16+
struct S {
17+
S() : x(42)
18+
{
19+
}
20+
21+
int x;
22+
};
23+
S s = S{};
24+
}
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/cpp/cpp_typecheck_expr.cpp

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -966,13 +966,8 @@ void cpp_typecheckt::typecheck_expr_explicit_constructor_call(exprt &expr)
966966
}
967967
else
968968
{
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-
974969
exprt e=expr;
975-
new_temporary(e.source_location(), tag, e.operands(), expr);
970+
new_temporary(e.source_location(), e.type(), e.operands(), expr);
976971
}
977972
}
978973

src/cpp/parse.cpp

Lines changed: 94 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -6363,7 +6363,10 @@ bool Parser::rAllocateInitializer(exprt &init)
63636363
postfix.exp
63646364
: primary.exp
63656365
| postfix.expr '[' comma.expression ']'
6366+
| postfix.expr '[' initializer ']'
63666367
| postfix.expr '(' function.arguments ')'
6368+
| integral.or.class.spec '(' function.arguments ')'
6369+
| integral.or.class.spec initializer
63676370
| postfix.expr '.' var.name
63686371
| postfix.expr ArrowOp var.name
63696372
| postfix.expr IncOp
@@ -6372,8 +6375,6 @@ bool Parser::rAllocateInitializer(exprt &init)
63726375
openc++.postfix.expr
63736376
: postfix.expr '.' userdef.statement
63746377
| postfix.expr ArrowOp userdef.statement
6375-
6376-
Note: function-style casts are accepted as function calls.
63776378
*/
63786379
bool Parser::rPostfixExpr(exprt &exp)
63796380
{
@@ -6382,8 +6383,89 @@ bool Parser::rPostfixExpr(exprt &exp)
63826383
std::cout << std::string(__indent, ' ') << "Parser::rPostfixExpr 0\n";
63836384
#endif
63846385

6385-
if(!rPrimaryExpr(exp))
6386-
return false;
6386+
typet type;
6387+
6388+
cpp_token_buffert::post pos=lex.Save();
6389+
// try to see whether this is explicit type conversion, else it has to be
6390+
// a primary-expression
6391+
if(optIntegralTypeOrClassSpec(type) &&
6392+
type.is_not_nil() &&
6393+
(lex.LookAhead(0) == '(' || lex.LookAhead(0) == '{'))
6394+
{
6395+
#ifdef DEBUG
6396+
std::cout << std::string(__indent, ' ') << "Parser::rPostfixExpr 0.1\n";
6397+
#endif
6398+
6399+
cpp_tokent tk;
6400+
lex.LookAhead(0, tk);
6401+
exprt exp2;
6402+
if(lex.LookAhead(0)=='{')
6403+
{
6404+
if(!rInitializeExpr(exp2))
6405+
return false;
6406+
}
6407+
else
6408+
{
6409+
// lex.LookAhead(0)=='('
6410+
lex.get_token(tk);
6411+
6412+
if(!rFunctionArguments(exp2))
6413+
return false;
6414+
6415+
cpp_tokent tk2;
6416+
if(lex.get_token(tk2)!=')')
6417+
return false;
6418+
}
6419+
6420+
exp=exprt("explicit-constructor-call");
6421+
exp.type().swap(type);
6422+
exp.operands().swap(exp2.operands());
6423+
set_location(exp, tk);
6424+
}
6425+
else
6426+
lex.Restore(pos);
6427+
6428+
exprt type_or_function_name;
6429+
if(rName(type_or_function_name) &&
6430+
(lex.LookAhead(0) == '(' || lex.LookAhead(0) == '{'))
6431+
{
6432+
#ifdef DEBUG
6433+
std::cout << std::string(__indent, ' ') << "Parser::rPostfixExpr 0.2\n";
6434+
#endif
6435+
6436+
cpp_tokent tk;
6437+
lex.LookAhead(0, tk);
6438+
exprt exp2;
6439+
if(lex.LookAhead(0)=='{')
6440+
{
6441+
if(!rInitializeExpr(exp2))
6442+
return false;
6443+
}
6444+
else
6445+
{
6446+
// lex.LookAhead(0)=='('
6447+
lex.get_token(tk);
6448+
6449+
if(!rFunctionArguments(exp2))
6450+
return false;
6451+
6452+
cpp_tokent tk2;
6453+
if(lex.get_token(tk2)!=')')
6454+
return false;
6455+
}
6456+
6457+
side_effect_expr_function_callt fc(
6458+
std::move(type_or_function_name), exp2.operands(), typet{}, source_locationt{});
6459+
set_location(fc, tk);
6460+
6461+
exp.swap(fc);
6462+
}
6463+
else
6464+
{
6465+
lex.Restore(pos);
6466+
if(!rPrimaryExpr(exp))
6467+
return false;
6468+
}
63876469

63886470
#ifdef DEBUG
63896471
std::cout << std::string(__indent, ' ') << "Parser::rPostfixExpr 1\n";
@@ -6399,7 +6481,14 @@ bool Parser::rPostfixExpr(exprt &exp)
63996481
{
64006482
case '[':
64016483
lex.get_token(op);
6402-
if(!rCommaExpression(e))
6484+
6485+
if(lex.LookAhead(0) == '{')
6486+
{
6487+
// C++11 initialisation expression
6488+
if(!rInitializeExpr(e))
6489+
return false;
6490+
}
6491+
else if(!rCommaExpression(e))
64036492
return false;
64046493

64056494
#ifdef DEBUG
@@ -6424,7 +6513,6 @@ bool Parser::rPostfixExpr(exprt &exp)
64246513
std::cout << std::string(__indent, ' ') << "Parser::rPostfixExpr 3\n";
64256514
#endif
64266515

6427-
lex.get_token(op);
64286516
if(!rFunctionArguments(e))
64296517
return false;
64306518

@@ -6718,8 +6806,6 @@ bool Parser::rTypePredicate(exprt &expr)
67186806
| THIS
67196807
| var.name
67206808
| '(' comma.expression ')'
6721-
| integral.or.class.spec '(' function.arguments ')'
6722-
| integral.or.class.spec initializer
67236809
| typeid.expr
67246810
| true
67256811
| false
@@ -6837,12 +6923,6 @@ bool Parser::rPrimaryExpr(exprt &exp)
68376923
#endif
68386924
return true;
68396925

6840-
case '{': // C++11 initialisation expression
6841-
#ifdef DEBUG
6842-
std::cout << std::string(__indent, ' ') << "Parser::rPrimaryExpr 10\n";
6843-
#endif
6844-
return rInitializeExpr(exp);
6845-
68466926
case TOK_TYPEID:
68476927
return rTypeidExpr(exp);
68486928

@@ -6873,60 +6953,6 @@ bool Parser::rPrimaryExpr(exprt &exp)
68736953
std::cout << std::string(__indent, ' ') << "Parser::rPrimaryExpr 14\n";
68746954
#endif
68756955
{
6876-
typet type;
6877-
6878-
if(!optIntegralTypeOrClassSpec(type))
6879-
return false;
6880-
6881-
#ifdef DEBUG
6882-
std::cout << std::string(__indent, ' ') << "Parser::rPrimaryExpr 15\n";
6883-
#endif
6884-
6885-
if(type.is_not_nil() && lex.LookAhead(0)==TOK_SCOPE)
6886-
{
6887-
lex.get_token(tk);
6888-
lex.get_token(tk);
6889-
6890-
// TODO
6891-
}
6892-
else if(type.is_not_nil())
6893-
{
6894-
#ifdef DEBUG
6895-
std::cout << std::string(__indent, ' ') << "Parser::rPrimaryExpr 16\n";
6896-
#endif
6897-
if(lex.LookAhead(0)=='{')
6898-
{
6899-
lex.LookAhead(0, tk);
6900-
6901-
exprt exp2;
6902-
if(!rInitializeExpr(exp2))
6903-
return false;
6904-
6905-
exp=exprt("explicit-constructor-call");
6906-
exp.type().swap(type);
6907-
exp.add_to_operands(std::move(exp2));
6908-
set_location(exp, tk);
6909-
}
6910-
else if(lex.LookAhead(0)=='(')
6911-
{
6912-
lex.get_token(tk);
6913-
6914-
exprt exp2;
6915-
if(!rFunctionArguments(exp2))
6916-
return false;
6917-
6918-
if(lex.get_token(tk2)!=')')
6919-
return false;
6920-
6921-
exp=exprt("explicit-constructor-call");
6922-
exp.type().swap(type);
6923-
exp.operands().swap(exp2.operands());
6924-
set_location(exp, tk);
6925-
}
6926-
else
6927-
return false;
6928-
}
6929-
else
69306956
{
69316957
if(!rVarName(exp))
69326958
return false;

0 commit comments

Comments
 (0)