Skip to content

Commit

Permalink
C++ front-end: support explicit type conversion with braced-init-list
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
tautschnig committed Jul 17, 2024
1 parent f529e30 commit 83b210e
Show file tree
Hide file tree
Showing 9 changed files with 336 additions and 189 deletions.
16 changes: 16 additions & 0 deletions regression/cbmc-cpp/Constructor7/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#include <cassert>

int main(int argc, char * argv[])
{
struct S {
S() : x(42)
{
}

int x;
};
S s = S{};

__CPROVER_assert(s.x == 42, "");
assert(s.x == 42);
}
8 changes: 8 additions & 0 deletions regression/cbmc-cpp/Constructor7/test.desc
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
CORE
main.cpp

^EXIT=0$
^SIGNAL=0$
^VERIFICATION SUCCESSFUL$
--
^warning: ignoring
24 changes: 24 additions & 0 deletions regression/cpp/brace_initializer1/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
struct __invoke_memfun_ref {};
constexpr bool __call_is_nt(__invoke_memfun_ref)
{
return false;
}

template<typename _Result>
struct __call_is_nothrow
{
constexpr static bool is_nt =
__call_is_nt(typename _Result::__invoke_type{});
};

int main(int argc, char * argv[])
{
struct S {
S() : x(42)
{
}

int x;
};
S s = S{};
}
8 changes: 8 additions & 0 deletions regression/cpp/brace_initializer1/test.desc
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
CORE
main.cpp
-std=c++11
^EXIT=0$
^SIGNAL=0$
--
^warning: ignoring
^CONVERSION ERROR$
4 changes: 4 additions & 0 deletions src/ansi-c/parser.y
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,10 @@ int yyansi_cerror(const std::string &error);
%token TOK_MSC_IF_EXISTS "__if_exists"
%token TOK_MSC_IF_NOT_EXISTS "__if_not_exists"
%token TOK_UNDERLYING_TYPE "__underlying_type"
%token TOK_DYNAMIC_CAST "dynamic_cast"
%token TOK_STATIC_CAST "static_cast"
%token TOK_REINTERPRET_CAST "reinterpret_cast"
%token TOK_CONST_CAST "const_cast"

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

Expand Down
5 changes: 5 additions & 0 deletions src/ansi-c/scanner.l
Original file line number Diff line number Diff line change
Expand Up @@ -1316,6 +1316,11 @@ __decltype { if(PARSER.cpp98 &&
return make_identifier();
}

"dynamic_cast" { return cpp98_keyword(TOK_DYNAMIC_CAST); }
"static_cast" { return cpp98_keyword(TOK_STATIC_CAST); }

Check warning on line 1320 in src/ansi-c/scanner.l

View check run for this annotation

Codecov / codecov/patch

src/ansi-c/scanner.l#L1319-L1320

Added lines #L1319 - L1320 were not covered by tests
"reinterpret_cast" { return cpp98_keyword(TOK_REINTERPRET_CAST); }
"const_cast" { return cpp98_keyword(TOK_CONST_CAST); }

{CPROVER_PREFIX}"atomic" { loc(); return TOK_CPROVER_ATOMIC; }
{CPROVER_PREFIX}"forall" { loc(); return TOK_FORALL; }
{CPROVER_PREFIX}"exists" { loc(); return TOK_EXISTS; }
Expand Down
4 changes: 4 additions & 0 deletions src/cpp/cpp_is_pod.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,10 @@ bool cpp_typecheckt::cpp_is_pod(const typet &type) const
{
return cpp_is_pod(to_array_type(type).element_type());
}
else if(type.id()==ID_vector)
{
return cpp_is_pod(to_vector_type(type).element_type());
}
else if(type.id()==ID_pointer)
{
if(is_reference(type)) // references are not PODs
Expand Down
78 changes: 12 additions & 66 deletions src/cpp/cpp_typecheck_expr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,13 @@ void cpp_typecheckt::typecheck_expr_main(exprt &expr)
{
expr.type().id(ID_initializer_list);
}
else if(expr.id() == ID_const_cast ||
expr.id() == ID_dynamic_cast ||
expr.id() == ID_reinterpret_cast ||
expr.id() == ID_static_cast)
{
typecheck_cast_expr(expr);
}
else
c_typecheck_baset::typecheck_expr_main(expr);
}
Expand Down Expand Up @@ -967,13 +974,8 @@ void cpp_typecheckt::typecheck_expr_explicit_constructor_call(exprt &expr)
}
else
{
CHECK_RETURN(expr.type().id() == ID_struct);

struct_tag_typet tag(expr.type().get(ID_name));
tag.add_source_location() = expr.source_location();

exprt e=expr;
new_temporary(e.source_location(), tag, e.operands(), expr);
new_temporary(e.source_location(), e.type(), e.operands(), expr);

Check warning on line 978 in src/cpp/cpp_typecheck_expr.cpp

View check run for this annotation

Codecov / codecov/patch

src/cpp/cpp_typecheck_expr.cpp#L978

Added line #L978 was not covered by tests
}
}

Expand Down Expand Up @@ -1275,53 +1277,20 @@ void cpp_typecheckt::typecheck_expr_ptrmember(

void cpp_typecheckt::typecheck_cast_expr(exprt &expr)
{
side_effect_expr_function_callt e =
to_side_effect_expr_function_call(expr);

if(e.arguments().size() != 1)
if(expr.operands().size() != 1)
{
error().source_location=expr.find_source_location();
error() << "cast expressions expect one operand" << eom;
throw 0;
}

exprt &f_op=e.function();
exprt &cast_op=e.arguments().front();
exprt &cast_op = to_unary_expr(expr).op();

add_implicit_dereference(cast_op);

const irep_idt &id=
f_op.get_sub().front().get(ID_identifier);

if(f_op.get_sub().size()!=2 ||
f_op.get_sub()[1].id()!=ID_template_args)
{
error().source_location=expr.find_source_location();
error() << id << " expects template argument" << eom;
throw 0;
}

irept &template_arguments=f_op.get_sub()[1].add(ID_arguments);

if(template_arguments.get_sub().size()!=1)
{
error().source_location=expr.find_source_location();
error() << id << " expects one template argument" << eom;
throw 0;
}

irept &template_arg=template_arguments.get_sub().front();

if(template_arg.id() != ID_type && template_arg.id() != ID_ambiguous)
{
error().source_location=expr.find_source_location();
error() << id << " expects a type as template argument" << eom;
throw 0;
}

typet &type=static_cast<typet &>(
template_arguments.get_sub().front().add(ID_type));
const irep_idt &id = expr.id();

typet &type = expr.type();
typecheck_type(type);

source_locationt source_location=expr.source_location();
Expand Down Expand Up @@ -1415,21 +1384,6 @@ void cpp_typecheckt::typecheck_expr_cpp_name(
}
}

if(expr.get_sub().size()>=1 &&
expr.get_sub().front().id()==ID_name)
{
const irep_idt &id=expr.get_sub().front().get(ID_identifier);

if(id==ID_const_cast ||
id==ID_dynamic_cast ||
id==ID_reinterpret_cast ||
id==ID_static_cast)
{
expr.id(ID_cast_expression);
return;
}
}

exprt symbol_expr=
resolve(
to_cpp_name(expr),
Expand Down Expand Up @@ -1556,14 +1510,6 @@ void cpp_typecheckt::typecheck_side_effect_function_call(

return;
}
else if(expr.function().id() == ID_cast_expression)
{
// These are not really function calls,
// but usually just type adjustments.
typecheck_cast_expr(expr);
add_implicit_dereference(expr);
return;
}
else if(expr.function().id() == ID_cpp_dummy_destructor)
{
// these don't do anything, e.g., (char*)->~char()
Expand Down
Loading

0 comments on commit 83b210e

Please sign in to comment.