diff options
-rw-r--r-- | include/clang/Parse/Parser.h | 7 | ||||
-rw-r--r-- | lib/Parse/ParseTentative.cpp | 60 | ||||
-rw-r--r-- | test/CXX/except/except.spec/p5-pointers.cpp | 6 | ||||
-rw-r--r-- | test/SemaCXX/unknown-type-name.cpp | 43 |
4 files changed, 98 insertions, 18 deletions
diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index bd5592cd33..814b45afc7 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -1753,7 +1753,8 @@ private: /// BracedCastResult. /// Doesn't consume tokens. TPResult - isCXXDeclarationSpecifier(TPResult BracedCastResult = TPResult::False()); + isCXXDeclarationSpecifier(TPResult BracedCastResult = TPResult::False(), + bool *HasMissingTypename = 0); // "Tentative parsing" functions, used for disambiguation. If a parsing error // is encountered they will return TPResult::Error(). @@ -1762,13 +1763,13 @@ private: // that more tentative parsing is necessary for disambiguation. // They all consume tokens, so backtracking should be used after calling them. - TPResult TryParseDeclarationSpecifier(); + TPResult TryParseDeclarationSpecifier(bool *HasMissingTypename = 0); TPResult TryParseSimpleDeclaration(bool AllowForRangeDecl); TPResult TryParseTypeofSpecifier(); TPResult TryParseProtocolQualifiers(); TPResult TryParseInitDeclaratorList(); TPResult TryParseDeclarator(bool mayBeAbstract, bool mayHaveIdentifier=true); - TPResult TryParseParameterDeclarationClause(); + TPResult TryParseParameterDeclarationClause(bool *InvalidAsDeclaration = 0); TPResult TryParseFunctionDeclarator(); TPResult TryParseBracketDeclarator(); diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp index e9685d25fe..c2e539ca61 100644 --- a/lib/Parse/ParseTentative.cpp +++ b/lib/Parse/ParseTentative.cpp @@ -827,6 +827,10 @@ Parser::isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind) { /// be either a decl-specifier or a function-style cast, and TPResult::Error() /// if a parsing error was found and reported. /// +/// If HasMissingTypename is provided, a name with a dependent scope specifier +/// will be treated as ambiguous if the 'typename' keyword is missing. If this +/// happens, *HasMissingTypename will be set to 'true'. +/// /// decl-specifier: /// storage-class-specifier /// type-specifier @@ -918,7 +922,8 @@ Parser::isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind) { /// [GNU] restrict /// Parser::TPResult -Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult) { +Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult, + bool *HasMissingTypename) { switch (Tok.getKind()) { case tok::identifier: // foo::bar // Check for need to substitute AltiVec __vector keyword @@ -936,7 +941,7 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult) { return (!getLangOpts().ObjC1 && Next.is(tok::identifier)) ? TPResult::True() : TPResult::False(); } - return isCXXDeclarationSpecifier(BracedCastResult); + return isCXXDeclarationSpecifier(BracedCastResult, HasMissingTypename); case tok::coloncolon: { // ::foo::bar const Token &Next = NextToken(); @@ -950,7 +955,7 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult) { // recurse to handle whatever we get. if (TryAnnotateTypeOrScopeToken()) return TPResult::Error(); - return isCXXDeclarationSpecifier(BracedCastResult); + return isCXXDeclarationSpecifier(BracedCastResult, HasMissingTypename); // decl-specifier: // storage-class-specifier @@ -1052,12 +1057,20 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult) { bool isIdentifier = Tok.is(tok::identifier); TPResult TPR = TPResult::False(); if (!isIdentifier) - TPR = isCXXDeclarationSpecifier(BracedCastResult); + TPR = isCXXDeclarationSpecifier(BracedCastResult, + HasMissingTypename); PA.Revert(); if (isIdentifier || TPR == TPResult::True() || TPR == TPResult::Error()) return TPResult::Error(); + + if (HasMissingTypename) { + // We can't tell whether this is a missing 'typename' or a valid + // expression. + *HasMissingTypename = true; + return TPResult::Ambiguous(); + } } } return TPResult::False(); @@ -1221,21 +1234,24 @@ Parser::TPResult Parser::TryParseProtocolQualifiers() { return TPResult::Error(); } -Parser::TPResult Parser::TryParseDeclarationSpecifier() { - TPResult TPR = isCXXDeclarationSpecifier(); +Parser::TPResult +Parser::TryParseDeclarationSpecifier(bool *HasMissingTypename) { + TPResult TPR = isCXXDeclarationSpecifier(TPResult::False(), + HasMissingTypename); if (TPR != TPResult::Ambiguous()) return TPR; if (Tok.is(tok::kw_typeof)) TryParseTypeofSpecifier(); else { + if (Tok.is(tok::annot_cxxscope)) + ConsumeToken(); ConsumeToken(); if (getLangOpts().ObjC1 && Tok.is(tok::less)) TryParseProtocolQualifiers(); } - assert(Tok.is(tok::l_paren) && "Expected '('!"); return TPResult::Ambiguous(); } @@ -1263,9 +1279,28 @@ bool Parser::isCXXFunctionDeclarator(bool warnIfAmbiguous) { TentativeParsingAction PA(*this); ConsumeParen(); - TPResult TPR = TryParseParameterDeclarationClause(); - if (TPR == TPResult::Ambiguous() && Tok.isNot(tok::r_paren)) - TPR = TPResult::False(); + bool InvalidAsDeclaration = false; + TPResult TPR = TryParseParameterDeclarationClause(&InvalidAsDeclaration); + if (TPR == TPResult::Ambiguous()) { + if (Tok.isNot(tok::r_paren)) + TPR = TPResult::False(); + else { + const Token &Next = NextToken(); + if (Next.is(tok::amp) || Next.is(tok::ampamp) || + Next.is(tok::kw_const) || Next.is(tok::kw_volatile) || + Next.is(tok::kw_throw) || Next.is(tok::kw_noexcept) || + Next.is(tok::l_square) || isCXX0XVirtSpecifier(Next) || + Next.is(tok::l_brace) || Next.is(tok::kw_try) || + Next.is(tok::equal)) + // The next token cannot appear after a constructor-style initializer, + // and can appear next in a function definition. This must be a function + // declarator. + TPR = TPResult::True(); + else if (InvalidAsDeclaration) + // Use the absence of 'typename' as a tie-breaker. + TPR = TPResult::False(); + } + } SourceLocation TPLoc = Tok.getLocation(); PA.Revert(); @@ -1303,7 +1338,8 @@ bool Parser::isCXXFunctionDeclarator(bool warnIfAmbiguous) { /// attribute-specifier-seq[opt] decl-specifier-seq abstract-declarator[opt] /// attributes[opt] '=' assignment-expression /// -Parser::TPResult Parser::TryParseParameterDeclarationClause() { +Parser::TPResult +Parser::TryParseParameterDeclarationClause(bool *InvalidAsDeclaration) { if (Tok.is(tok::r_paren)) return TPResult::True(); @@ -1336,7 +1372,7 @@ Parser::TPResult Parser::TryParseParameterDeclarationClause() { // decl-specifier-seq // A parameter-declaration's initializer must be preceded by an '=', so // decl-specifier-seq '{' is not a parameter in C++11. - TPResult TPR = TryParseDeclarationSpecifier(); + TPResult TPR = TryParseDeclarationSpecifier(InvalidAsDeclaration); if (TPR != TPResult::Ambiguous()) return TPR; diff --git a/test/CXX/except/except.spec/p5-pointers.cpp b/test/CXX/except/except.spec/p5-pointers.cpp index dd3c0600ce..f855520aa2 100644 --- a/test/CXX/except/except.spec/p5-pointers.cpp +++ b/test/CXX/except/except.spec/p5-pointers.cpp @@ -65,9 +65,9 @@ void fnptrs() void (*(*t7)())() throw(B1) = &s8; // valid void (*(*t8)())() throw(A) = &s8; // expected-error {{return types differ}} void (*(*t9)())() throw(D) = &s8; // expected-error {{return types differ}} - void (*t10)(void (*)() throw(B1)) = &s9; // valid expected-warning{{disambiguated}} - void (*t11)(void (*)() throw(A)) = &s9; // expected-error {{argument types differ}} expected-warning{{disambiguated}} - void (*t12)(void (*)() throw(D)) = &s9; // expected-error {{argument types differ}} expected-warning{{disambiguated}} + void (*t10)(void (*)() throw(B1)) = &s9; // valid + void (*t11)(void (*)() throw(A)) = &s9; // expected-error {{argument types differ}} + void (*t12)(void (*)() throw(D)) = &s9; // expected-error {{argument types differ}} } // Member function stuff diff --git a/test/SemaCXX/unknown-type-name.cpp b/test/SemaCXX/unknown-type-name.cpp index 7912fbec3f..893e0cc5dc 100644 --- a/test/SemaCXX/unknown-type-name.cpp +++ b/test/SemaCXX/unknown-type-name.cpp @@ -22,6 +22,11 @@ struct A { type f(); type g(); + + static int n; + static type m; + static int h(T::type, int); // expected-error{{missing 'typename'}} + static int h(T::type x, char); // expected-error{{missing 'typename'}} }; template<typename T> @@ -31,11 +36,49 @@ template<typename T> A<T>::type A<T>::f() { return type(); } // expected-error{{missing 'typename'}} template<typename T> +void f(T::type) { } // expected-error{{missing 'typename'}} + +template<typename T> +void g(T::type x) { } // expected-error{{missing 'typename'}} + +template<typename T> +void f(T::type, int) { } // expected-error{{missing 'typename'}} + +template<typename T> +void f(T::type x, char) { } // expected-error{{missing 'typename'}} + +template<typename T> void f(int, T::type) { } // expected-error{{missing 'typename'}} template<typename T> +void f(char, T::type x) { } // expected-error{{missing 'typename'}} + +template<typename T> void f(int, T::type, int) { } // expected-error{{missing 'typename'}} +template<typename T> +void f(int, T::type x, char) { } // expected-error{{missing 'typename'}} + +template<typename T> int A<T>::n(T::value); // ok +template<typename T> +A<T>::type // expected-error{{missing 'typename'}} +A<T>::m(T::value, 0); // ok + +template<typename T> int A<T>::h(T::type, int) {} // expected-error{{missing 'typename'}} +template<typename T> int A<T>::h(T::type x, char) {} // expected-error{{missing 'typename'}} + +template<typename T> int h(T::type, int); // expected-error{{missing 'typename'}} +template<typename T> int h(T::type x, char); // expected-error{{missing 'typename'}} + +template<typename T> int junk1(T::junk); // expected-error{{declared as a template}} +template<typename T> int junk2(T::junk) throw(); // expected-error{{missing 'typename'}} +template<typename T> int junk3(T::junk) = delete; // expected-error{{missing 'typename'}} expected-warning{{C++11}} +template<typename T> int junk4(T::junk j); // expected-error{{missing 'typename'}} + +// FIXME: We can tell this was intended to be a function because it does not +// have a dependent nested name specifier. +template<typename T> int i(T::type, int()); // expected-error{{variable 'i' declared as a template}} + // FIXME: We know which type specifier should have been specified here. Provide // a fix-it to add 'typename A<T>::type' template<typename T> |