Skip to content

Commit bd74d87

Browse files
authored
Merge pull request diffblue#2343 from tautschnig/c++-auto
C++11 auto type specifier
2 parents 278e506 + af83568 commit bd74d87

16 files changed

+124
-8
lines changed

regression/cpp/auto1/test.desc

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

regression/cpp/auto2/main.cpp

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
int main()
2+
{
3+
#ifndef _MSC_VER
4+
// Visual Studio uses C++14 by default, thus the below would not be valid
5+
auto int x = 42;
6+
#endif
7+
}

regression/cpp/auto2/test.desc

+8
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+
--
7+
^warning: ignoring
8+
^CONVERSION ERROR$

regression/cpp/auto3/main.cpp

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
int main()
2+
{
3+
#ifndef _MSC_VER
4+
// should yield a parse error unless in C++11 (or later) mode
5+
auto x = 42;
6+
const auto y = 42;
7+
const auto &z = y;
8+
#else
9+
intentionally invalid
10+
#endif
11+
}

regression/cpp/auto3/test.desc

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
CORE
2+
main.cpp
3+
4+
^EXIT=(64|1)$
5+
^SIGNAL=0$
6+
parse error
7+
--
8+
^warning: ignoring
9+
^CONVERSION ERROR$

regression/cpp/auto4/main.cpp

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
int main()
2+
{
3+
auto x = 42;
4+
const auto y = 42;
5+
const auto &z = y;
6+
}

regression/cpp/auto4/test.desc

+8
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_convert_type.cpp

+16
Original file line numberDiff line numberDiff line change
@@ -591,3 +591,19 @@ void cpp_convert_plain_type(typet &type)
591591
cpp_convert_type.write(type);
592592
}
593593
}
594+
595+
void cpp_convert_auto(typet &dest, const typet &src)
596+
{
597+
if(dest.id() != ID_merged_type && dest.has_subtype())
598+
{
599+
cpp_convert_auto(dest.subtype(), src);
600+
return;
601+
}
602+
603+
cpp_convert_typet cpp_convert_type(dest);
604+
for(auto &t : cpp_convert_type.other)
605+
if(t.id() == ID_auto)
606+
t = src;
607+
608+
cpp_convert_type.write(dest);
609+
}

src/cpp/cpp_convert_type.h

+2
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,6 @@ Author: Daniel Kroening, [email protected]
1616

1717
void cpp_convert_plain_type(typet &);
1818

19+
void cpp_convert_auto(typet &dest, const typet &src);
20+
1921
#endif // CPROVER_CPP_CPP_CONVERT_TYPE_H

src/cpp/cpp_declarator_converter.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,8 @@ symbolt &cpp_declarator_convertert::convert(
6868
scope=&cpp_typecheck.cpp_scopes.current_scope();
6969

7070
// check the declarator-part of the type, in that scope
71-
cpp_typecheck.typecheck_type(final_type);
71+
if(declarator.value().is_nil() || !cpp_typecheck.has_auto(final_type))
72+
cpp_typecheck.typecheck_type(final_type);
7273
}
7374

7475
is_code=is_code_type(final_type);

src/cpp/cpp_typecheck.h

+1
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,7 @@ class cpp_typecheckt:public c_typecheck_baset
395395

396396
static bool has_const(const typet &type);
397397
static bool has_volatile(const typet &type);
398+
static bool has_auto(const typet &type);
398399

399400
void typecheck_member_function(
400401
const irep_idt &compound_identifier,

src/cpp/cpp_typecheck_code.cpp

+7-2
Original file line numberDiff line numberDiff line change
@@ -368,7 +368,9 @@ void cpp_typecheckt::typecheck_decl(codet &code)
368368

369369
bool is_typedef=declaration.is_typedef();
370370

371-
typecheck_type(type);
371+
if(declaration.declarators().empty() || !has_auto(type))
372+
typecheck_type(type);
373+
372374
assert(type.is_not_nil());
373375

374376
if(declaration.declarators().empty() &&
@@ -409,7 +411,10 @@ void cpp_typecheckt::typecheck_decl(codet &code)
409411
symbol.value.id()!=ID_code)
410412
{
411413
decl_statement.copy_to_operands(symbol.value);
412-
assert(follow(decl_statement.op1().type())==follow(symbol.type));
414+
DATA_INVARIANT(
415+
has_auto(symbol.type) ||
416+
follow(decl_statement.op1().type()) == follow(symbol.type),
417+
"declarator type should match symbol type");
413418
}
414419

415420
new_code.move_to_operands(decl_statement);

src/cpp/cpp_typecheck_compound_type.cpp

+16
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,22 @@ bool cpp_typecheckt::has_volatile(const typet &type)
5757
return false;
5858
}
5959

60+
bool cpp_typecheckt::has_auto(const typet &type)
61+
{
62+
if(type.id() == ID_auto)
63+
return true;
64+
else if(type.id() == ID_merged_type || type.id() == ID_frontend_pointer)
65+
{
66+
forall_subtypes(it, type)
67+
if(has_auto(*it))
68+
return true;
69+
70+
return false;
71+
}
72+
else
73+
return false;
74+
}
75+
6076
cpp_scopet &cpp_typecheckt::tag_scope(
6177
const irep_idt &base_name,
6278
bool has_body,

src/cpp/cpp_typecheck_declaration.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,8 @@ void cpp_typecheckt::convert_non_template_declaration(
122122
declaration.name_anon_struct_union();
123123

124124
// do the type of the declaration
125-
typecheck_type(declaration_type);
125+
if(declaration.declarators().empty() || !has_auto(declaration_type))
126+
typecheck_type(declaration_type);
126127

127128
// Elaborate any class template instance _unless_ we do a typedef.
128129
// These are only elaborated on usage!

src/cpp/cpp_typecheck_initializer.cpp

+8
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ Author: Daniel Kroening, [email protected]
1616
#include <util/expr_initializer.h>
1717
#include <util/pointer_offset_size.h>
1818

19+
#include "cpp_convert_type.h"
20+
1921
/// Initialize an object with a value
2022
void cpp_typecheckt::convert_initializer(symbolt &symbol)
2123
{
@@ -144,6 +146,12 @@ void cpp_typecheckt::convert_initializer(symbolt &symbol)
144146
if(symbol.type.find(ID_size).is_nil())
145147
symbol.type=symbol.value.type();
146148
}
149+
else if(has_auto(symbol.type))
150+
{
151+
cpp_convert_auto(symbol.type, symbol.value.type());
152+
typecheck_type(symbol.type);
153+
implicit_typecast(symbol.value, symbol.type);
154+
}
147155
else
148156
implicit_typecast(symbol.value, symbol.type);
149157

src/cpp/parse.cpp

+20-3
Original file line numberDiff line numberDiff line change
@@ -1442,7 +1442,7 @@ bool Parser::rDeclaration(cpp_declarationt &declaration)
14421442
<< "\n";
14431443
#endif
14441444

1445-
if((cv_q.is_not_nil() || storage_spec.is_auto()) &&
1445+
if(cv_q.is_not_nil() &&
14461446
((t==TOK_IDENTIFIER && lex.LookAhead(1)=='=') || t=='*'))
14471447
return rConstDeclaration(declaration, storage_spec, member_spec, cv_q);
14481448
else
@@ -1585,6 +1585,17 @@ bool Parser::rIntegralDeclaration(
15851585
if(!rDeclarators(declaration.declarators(), true))
15861586
return false;
15871587

1588+
// handle trailing return type
1589+
if(
1590+
declaration.type().id() == ID_auto &&
1591+
declaration.declarators().size() == 1 &&
1592+
declaration.declarators().front().type().id() == ID_function_type &&
1593+
declaration.declarators().front().type().subtype().is_not_nil())
1594+
{
1595+
declaration.type() = declaration.declarators().front().type().subtype();
1596+
declaration.declarators().front().type().subtype().make_nil();
1597+
}
1598+
15881599
#ifdef DEBUG
15891600
std::cout << std::string(__indent, ' ')
15901601
<< "Parser::rIntegralDeclaration 7\n";
@@ -1961,7 +1972,7 @@ bool Parser::optStorageSpec(cpp_storage_spect &storage_spec)
19611972

19621973
if(t==TOK_STATIC ||
19631974
t==TOK_EXTERN ||
1964-
t==TOK_AUTO ||
1975+
(t == TOK_AUTO && !ansi_c_parser.cpp11) ||
19651976
t==TOK_REGISTER ||
19661977
t==TOK_MUTABLE ||
19671978
t==TOK_GCC_ASM ||
@@ -2224,6 +2235,7 @@ bool Parser::optIntegralTypeOrClassSpec(typet &p)
22242235
case TOK_GCC_FLOAT128: type_id=ID_gcc_float128; break;
22252236
case TOK_BOOL: type_id=ID_bool; break;
22262237
case TOK_CPROVER_BOOL: type_id=ID_proper_bool; break;
2238+
case TOK_AUTO: type_id = ID_auto; break;
22272239
default: type_id=irep_idt();
22282240
}
22292241

@@ -2912,6 +2924,11 @@ bool Parser::rDeclarator(
29122924
typet return_type;
29132925
if(!rTypeSpecifier(return_type, false))
29142926
return false;
2927+
2928+
if(d_outer.subtype().is_not_nil())
2929+
return false;
2930+
2931+
d_outer.subtype().swap(return_type);
29152932
}
29162933

29172934
if(lex.LookAhead(0)==':')
@@ -7997,7 +8014,7 @@ bool Parser::rDeclarationStatement(codet &statement)
79978014
<< "Parser::rDeclarationStatement 3 " << t << "\n";
79988015
#endif
79998016

8000-
if((cv_q.is_not_nil() || storage_spec.is_auto()) &&
8017+
if(cv_q.is_not_nil() &&
80018018
((t==TOK_IDENTIFIER && lex.LookAhead(1)=='=') || t=='*'))
80028019
{
80038020
#ifdef DEBUG

0 commit comments

Comments
 (0)