mirror of https://github.com/microsoft/clang.git
Accept braced-init-lists in conditions, and, in passing, dramatically improve
the diagnostic for using a parenthesized direct-initializer in a condition. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@151137 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
b1e3f324b0
commit
0635aa75ab
|
@ -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>;
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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).
|
||||
|
||||
|
|
|
@ -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; }
|
||||
}
|
||||
|
||||
|
|
|
@ -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}}
|
||||
}
|
||||
|
|
|
@ -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 '='?}}
|
||||
}
|
|
@ -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() {
|
||||
|
|
Loading…
Reference in New Issue