diff options
-rw-r--r-- | include/clang/Basic/DiagnosticParseKinds.td | 6 | ||||
-rw-r--r-- | include/clang/Sema/DeclSpec.h | 7 | ||||
-rw-r--r-- | lib/Parse/ParseExprCXX.cpp | 35 | ||||
-rw-r--r-- | test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3.cpp | 6 | ||||
-rw-r--r-- | test/Parser/cxx-condition.cpp | 6 | ||||
-rw-r--r-- | test/Parser/cxx0x-condition.cpp | 37 | ||||
-rw-r--r-- | test/SemaCXX/cxx0x-initializer-scalars.cpp | 2 |
7 files changed, 84 insertions, 15 deletions
diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td index 744a96ebbb..3eb12dee47 100644 --- a/include/clang/Basic/DiagnosticParseKinds.td +++ b/include/clang/Basic/DiagnosticParseKinds.td @@ -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>; diff --git a/include/clang/Sema/DeclSpec.h b/include/clang/Sema/DeclSpec.h index 45cf8e3e68..f5c2999616 100644 --- a/include/clang/Sema/DeclSpec.h +++ b/include/clang/Sema/DeclSpec.h @@ -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: diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index af532de385..ccd038cb21 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -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). diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3.cpp index 0219185a9f..1daf02f6ea 100644 --- a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3.cpp +++ b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3.cpp @@ -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; } } diff --git a/test/Parser/cxx-condition.cpp b/test/Parser/cxx-condition.cpp index 5b07842929..5672eea72b 100644 --- a/test/Parser/cxx-condition.cpp +++ b/test/Parser/cxx-condition.cpp @@ -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}} } diff --git a/test/Parser/cxx0x-condition.cpp b/test/Parser/cxx0x-condition.cpp new file mode 100644 index 0000000000..ce7d1a8aef --- /dev/null +++ b/test/Parser/cxx0x-condition.cpp @@ -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 '='?}} +} diff --git a/test/SemaCXX/cxx0x-initializer-scalars.cpp b/test/SemaCXX/cxx0x-initializer-scalars.cpp index 49f53b6057..8d25443da8 100644 --- a/test/SemaCXX/cxx0x-initializer-scalars.cpp +++ b/test/SemaCXX/cxx0x-initializer-scalars.cpp @@ -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() { |