Accept braced-init-lists in conditions, and, in passing, dramatically improve

the diagnostic for using a parenthesized direct-initializer in a condition.

llvm-svn: 151137
This commit is contained in:
Richard Smith 2012-02-22 06:49:09 +00:00
parent db42c6faa4
commit 2a15b74605
7 changed files with 84 additions and 15 deletions

View File

@ -381,8 +381,10 @@ def err_func_def_no_params : Error<
"function definition does not declare parameters">;
def err_expected_lparen_after_type : Error<
"expected '(' for function-style cast or type construction">;
def err_expected_equal_after_declarator : Error<
"expected '=' after declarator">;
def err_expected_init_in_condition : Error<
"variable declaration in condition must have an initializer">;
def err_expected_init_in_condition_lparen : Error<
"variable declaration in condition cannot have a parenthesized initializer">;
def warn_parens_disambiguated_as_function_decl : Warning<
"parentheses were disambiguated as a function declarator">,
InGroup<VexingParse>;

View File

@ -1645,9 +1645,14 @@ public:
case ForContext:
return true;
case ConditionContext:
// This may not be followed by a direct initializer, but it can't be a
// function declaration either, and we'd prefer to perform a tentative
// parse in order to produce the right diagnostic.
return true;
case KNRTypeListContext:
case MemberContext:
case ConditionContext:
case PrototypeContext:
case ObjCParameterContext:
case ObjCResultContext:

View File

@ -1271,6 +1271,8 @@ Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) {
/// condition:
/// expression
/// type-specifier-seq declarator '=' assignment-expression
/// [C++11] type-specifier-seq declarator '=' initializer-clause
/// [C++11] type-specifier-seq declarator braced-init-list
/// [GNU] type-specifier-seq declarator simple-asm-expr[opt] attributes[opt]
/// '=' assignment-expression
///
@ -1342,17 +1344,34 @@ bool Parser::ParseCXXCondition(ExprResult &ExprOut,
// '=' assignment-expression
// If a '==' or '+=' is found, suggest a fixit to '='.
if (isTokenEqualOrEqualTypo()) {
bool CopyInitialization = isTokenEqualOrEqualTypo();
if (CopyInitialization)
ConsumeToken();
ExprResult AssignExpr(ParseAssignmentExpression());
if (!AssignExpr.isInvalid())
Actions.AddInitializerToDecl(DeclOut, AssignExpr.take(), false,
DS.getTypeSpecType() == DeclSpec::TST_auto);
ExprResult InitExpr = ExprError();
if (getLang().CPlusPlus0x && Tok.is(tok::l_brace)) {
Diag(Tok.getLocation(),
diag::warn_cxx98_compat_generalized_initializer_lists);
InitExpr = ParseBraceInitializer();
} else if (CopyInitialization) {
InitExpr = ParseAssignmentExpression();
} else if (Tok.is(tok::l_paren)) {
// This was probably an attempt to initialize the variable.
SourceLocation LParen = ConsumeParen(), RParen = LParen;
if (SkipUntil(tok::r_paren, true, /*DontConsume=*/true))
RParen = ConsumeParen();
Diag(DeclOut ? DeclOut->getLocation() : LParen,
diag::err_expected_init_in_condition_lparen)
<< SourceRange(LParen, RParen);
} else {
// FIXME: C++0x allows a braced-init-list
Diag(Tok, diag::err_expected_equal_after_declarator);
Diag(DeclOut ? DeclOut->getLocation() : Tok.getLocation(),
diag::err_expected_init_in_condition);
}
if (!InitExpr.isInvalid())
Actions.AddInitializerToDecl(DeclOut, InitExpr.take(), !CopyInitialization,
DS.getTypeSpecType() == DeclSpec::TST_auto);
// FIXME: Build a reference to this declaration? Convert it to bool?
// (This is currently handled by Sema).

View File

@ -13,9 +13,9 @@ void g() {
auto *b; // expected-error{{declaration of variable 'b' with type 'auto *' requires an initializer}}
if (auto b) {} // expected-error {{expected '='}}
for (;auto b;) {} // expected-error {{expected '='}}
while (auto b) {} // expected-error {{expected '='}}
if (auto b) {} // expected-error {{must have an initializer}}
for (;auto b;) {} // expected-error {{must have an initializer}}
while (auto b) {} // expected-error {{must have an initializer}}
if (auto b = true) { (void)b; }
}

View File

@ -1,11 +1,15 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
struct S { S(int); operator bool(); };
void f() {
int a;
while (a) ;
while (int x) ; // expected-error {{expected '=' after declarator}}
while (int x) ; // expected-error {{variable declaration in condition must have an initializer}}
while (float x = 0) ;
if (const int x = a) ; // expected-warning{{empty body}} expected-note{{put the semicolon on a separate line to silence this warning}}
switch (int x = a+10) {}
for (; int x = ++a; ) ;
if (S a(42)) {} // expected-error {{variable declaration in condition cannot have a parenthesized initializer}}
}

View File

@ -0,0 +1,37 @@
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
struct S { S(int); operator bool(); };
void f() {
int a;
typedef int n;
while (a) ;
while (int x) ; // expected-error {{variable declaration in condition must have an initializer}}
while (float x = 0) ;
if (const int x = a) ; // expected-warning{{empty body}} expected-note{{put the semicolon on a separate line to silence this warning}}
switch (int x = a+10) {}
for (; int x = ++a; ) ;
if (S(a)) {} // ok
if (S(a) = 0) {} // ok
if (S(a) == 0) {} // ok
if (S(n)) {} // expected-error {{unexpected type name 'n': expected expression}}
if (S(n) = 0) {} // ok
if (S(n) == 0) {} // expected-error {{unexpected type name 'n': expected expression}}
if (S b(a)) {} // expected-error {{variable declaration in condition cannot have a parenthesized initializer}}
if (S b(n)) {} // expected-error {{a function type is not allowed here}} expected-error {{must have an initializer}}
if (S b(n) = 0) {} // expected-error {{a function type is not allowed here}}
if (S b(n) == 0) {} // expected-error {{a function type is not allowed here}} expected-error {{did you mean '='?}}
// FIXME: this is legal, and incorrectly rejected, because tentative parsing
// does not yet know about braced function-style casts.
if (S{a}) {} // unexpected-error{{unqualified-id}}
if (S a{a}) {} // ok
if (S a = {a}) {} // ok
if (S a == {a}) {} // expected-error {{did you mean '='?}}
}

View File

@ -15,6 +15,8 @@ namespace integral {
// FIXME: Redundant warnings.
{ const short a{100000}; } // expected-error {{cannot be narrowed}} expected-note {{inserting an explicit cast}} expected-warning {{changes value}}
{ const short a = {100000}; } // expected-error {{cannot be narrowed}} expected-note {{inserting an explicit cast}} expected-warning {{changes value}}
{ if (const int a{1}) static_assert(a == 1, ""); }
{ if (const int a = {1}) static_assert(a == 1, ""); }
}
int direct_usage() {