diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2015-02-23 21:16:05 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2015-02-23 21:16:05 +0000 |
commit | 152a172899034b5f9c34420621cd9cfa74c68efa (patch) | |
tree | 047c268b46d9e8d7de38ab6bf228e03b5ca9fd4c | |
parent | 0168d34e238cb928c05309caac4eb4d50e739b0c (diff) | |
download | bcm5719-llvm-152a172899034b5f9c34420621cd9cfa74c68efa.tar.gz bcm5719-llvm-152a172899034b5f9c34420621cd9cfa74c68efa.zip |
Improve declaration / expression disambiguation around ptr-operators, and use
the presence of an abstract declarator with a ptr-operator as proof that a
construct cannot parse as an expression to improve diagnostics along error
recovery paths.
llvm-svn: 230261
-rw-r--r-- | clang/include/clang/Parse/Parser.h | 5 | ||||
-rw-r--r-- | clang/lib/Parse/ParseTentative.cpp | 66 | ||||
-rw-r--r-- | clang/test/Parser/cxx-ambig-init-templ.cpp | 9 | ||||
-rw-r--r-- | clang/test/Parser/cxx-variadic-func.cpp | 3 | ||||
-rw-r--r-- | clang/test/Parser/recovery.cpp | 8 | ||||
-rw-r--r-- | clang/test/SemaTemplate/rdar9173693.cpp | 4 |
6 files changed, 67 insertions, 28 deletions
diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index fd120aef294..2cfc5e23dd7 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -1941,11 +1941,12 @@ private: TPResult TryParsePtrOperatorSeq(); TPResult TryParseOperatorId(); TPResult TryParseInitDeclaratorList(); - TPResult TryParseDeclarator(bool mayBeAbstract, bool mayHaveIdentifier=true); + TPResult TryParseDeclarator(bool MayBeAbstract, bool MayHaveIdentifier = true, + bool VersusExpression = true); TPResult TryParseParameterDeclarationClause(bool *InvalidAsDeclaration = nullptr, bool VersusTemplateArg = false); - TPResult TryParseFunctionDeclarator(); + TPResult TryParseFunctionDeclarator(bool VersusExpression = true); TPResult TryParseBracketDeclarator(); TPResult TryConsumeDeclarationSpecifier(); diff --git a/clang/lib/Parse/ParseTentative.cpp b/clang/lib/Parse/ParseTentative.cpp index abf16fa6222..29ee467b6ad 100644 --- a/clang/lib/Parse/ParseTentative.cpp +++ b/clang/lib/Parse/ParseTentative.cpp @@ -284,7 +284,7 @@ Parser::TPResult Parser::TryParseSimpleDeclaration(bool AllowForRangeDecl) { Parser::TPResult Parser::TryParseInitDeclaratorList() { while (1) { // declarator - TPResult TPR = TryParseDeclarator(false/*mayBeAbstract*/); + TPResult TPR = TryParseDeclarator(false/*MayBeAbstract*/); if (TPR != TPResult::Ambiguous) return TPR; @@ -361,7 +361,7 @@ bool Parser::isCXXConditionDeclaration() { assert(Tok.is(tok::l_paren) && "Expected '('"); // declarator - TPR = TryParseDeclarator(false/*mayBeAbstract*/); + TPR = TryParseDeclarator(false/*MayBeAbstract*/); // In case of an error, let the declaration parsing code handle it. if (TPR == TPResult::Error) @@ -431,7 +431,7 @@ bool Parser::isCXXTypeId(TentativeCXXTypeIdContext Context, bool &isAmbiguous) { assert(Tok.is(tok::l_paren) && "Expected '('"); // declarator - TPR = TryParseDeclarator(true/*mayBeAbstract*/, false/*mayHaveIdentifier*/); + TPR = TryParseDeclarator(/*MayBeAbstract*/true, /*MayHaveIdentifier*/false); // In case of an error, let the declaration parsing code handle it. if (TPR == TPResult::Error) @@ -623,6 +623,7 @@ Parser::isCXX11AttributeSpecifier(bool Disambiguate, } Parser::TPResult Parser::TryParsePtrOperatorSeq() { + bool ConsumedAny = false; while (true) { if (Tok.is(tok::coloncolon) || Tok.is(tok::identifier)) if (TryAnnotateCXXScopeToken(true)) @@ -637,8 +638,9 @@ Parser::TPResult Parser::TryParsePtrOperatorSeq() { Tok.is(tok::kw_volatile) || Tok.is(tok::kw_restrict)) ConsumeToken(); + ConsumedAny = true; } else { - return TPResult::True; + return ConsumedAny ? TPResult::True : TPResult::False; } } } @@ -734,7 +736,8 @@ Parser::TPResult Parser::TryParseOperatorId() { return TPResult::Error; AnyDeclSpecifiers = true; } - return TryParsePtrOperatorSeq(); + return TryParsePtrOperatorSeq() == TPResult::Error ? TPResult::Error + : TPResult::True; } /// declarator: @@ -790,13 +793,23 @@ Parser::TPResult Parser::TryParseOperatorId() { /// '~' decltype-specifier [TODO] /// template-id [TODO] /// -Parser::TPResult Parser::TryParseDeclarator(bool mayBeAbstract, - bool mayHaveIdentifier) { +Parser::TPResult Parser::TryParseDeclarator(bool MayBeAbstract, + bool MayHaveIdentifier, + bool VersusExpression) { // declarator: // direct-declarator // ptr-operator declarator - if (TryParsePtrOperatorSeq() == TPResult::Error) - return TPResult::Error; + { + TPResult TPR = TryParsePtrOperatorSeq(); + if (TPR == TPResult::Error) + return TPResult::Error; + // After a ptr-operator, any of ')', ',', ';', and '...' indicates + // that this cannot be an expression. + if (VersusExpression && TPR == TPResult::True && + (Tok.is(tok::r_paren) || Tok.is(tok::comma) || Tok.is(tok::ellipsis) || + Tok.is(tok::semi))) + return TPResult::True; + } // direct-declarator: // direct-abstract-declarator: @@ -806,7 +819,7 @@ Parser::TPResult Parser::TryParseDeclarator(bool mayBeAbstract, if ((Tok.is(tok::identifier) || Tok.is(tok::kw_operator) || (Tok.is(tok::annot_cxxscope) && (NextToken().is(tok::identifier) || NextToken().is(tok::kw_operator)))) && - mayHaveIdentifier) { + MayHaveIdentifier) { // declarator-id if (Tok.is(tok::annot_cxxscope)) ConsumeToken(); @@ -819,14 +832,14 @@ Parser::TPResult Parser::TryParseDeclarator(bool mayBeAbstract, ConsumeToken(); } else if (Tok.is(tok::l_paren)) { ConsumeParen(); - if (mayBeAbstract && + if (MayBeAbstract && (Tok.is(tok::r_paren) || // 'int()' is a function. // 'int(...)' is a function. (Tok.is(tok::ellipsis) && NextToken().is(tok::r_paren)) || isDeclarationSpecifier())) { // 'int(int)' is a function. // '(' parameter-declaration-clause ')' cv-qualifier-seq[opt] // exception-specification[opt] - TPResult TPR = TryParseFunctionDeclarator(); + TPResult TPR = TryParseFunctionDeclarator(VersusExpression); if (TPR != TPResult::Ambiguous) return TPR; } else { @@ -842,14 +855,15 @@ Parser::TPResult Parser::TryParseDeclarator(bool mayBeAbstract, Tok.is(tok::kw___vectorcall) || Tok.is(tok::kw___unaligned)) return TPResult::True; // attributes indicate declaration - TPResult TPR = TryParseDeclarator(mayBeAbstract, mayHaveIdentifier); + TPResult TPR = TryParseDeclarator(MayBeAbstract, MayHaveIdentifier, + VersusExpression); if (TPR != TPResult::Ambiguous) return TPR; if (Tok.isNot(tok::r_paren)) return TPResult::False; ConsumeParen(); } - } else if (!mayBeAbstract) { + } else if (!MayBeAbstract) { return TPResult::False; } @@ -865,13 +879,13 @@ Parser::TPResult Parser::TryParseDeclarator(bool mayBeAbstract, // initializer that follows the declarator. Note that ctor-style // initializers are not possible in contexts where abstract declarators // are allowed. - if (!mayBeAbstract && !isCXXFunctionDeclarator()) + if (!MayBeAbstract && !isCXXFunctionDeclarator()) break; // direct-declarator '(' parameter-declaration-clause ')' // cv-qualifier-seq[opt] exception-specification[opt] ConsumeParen(); - TPR = TryParseFunctionDeclarator(); + TPR = TryParseFunctionDeclarator(VersusExpression); } else if (Tok.is(tok::l_square)) { // direct-declarator '[' constant-expression[opt] ']' // direct-abstract-declarator[opt] '[' constant-expression[opt] ']' @@ -1710,7 +1724,8 @@ Parser::TryParseParameterDeclarationClause(bool *InvalidAsDeclaration, // declarator // abstract-declarator[opt] - TPR = TryParseDeclarator(true/*mayBeAbstract*/); + TPR = TryParseDeclarator(/*MayBeAbstract*/true, /*MayHaveIdentifier*/true, + /*VersusExpression*/!VersusTemplateArgument); if (TPR != TPResult::Ambiguous) return TPR; @@ -1757,9 +1772,15 @@ Parser::TryParseParameterDeclarationClause(bool *InvalidAsDeclaration, /// TryParseFunctionDeclarator - We parsed a '(' and we want to try to continue /// parsing as a function declarator. +/// /// If TryParseFunctionDeclarator fully parsed the function declarator, it will -/// return TPResult::Ambiguous, otherwise it will return either False() or -/// Error(). +/// return TPResult::Ambiguous. +/// +/// If \p VersusExpression is true and this cannot be a function-style +/// cast expression, returns TPResult::True. +/// +/// Otherwise, returns TPResult::False if this can't be a function declarator +/// and TPResult::Error if it can't be anything. /// /// '(' parameter-declaration-clause ')' cv-qualifier-seq[opt] /// exception-specification[opt] @@ -1767,7 +1788,7 @@ Parser::TryParseParameterDeclarationClause(bool *InvalidAsDeclaration, /// exception-specification: /// 'throw' '(' type-id-list[opt] ')' /// -Parser::TPResult Parser::TryParseFunctionDeclarator() { +Parser::TPResult Parser::TryParseFunctionDeclarator(bool VersusExpression) { // The '(' is already parsed. @@ -1775,8 +1796,9 @@ Parser::TPResult Parser::TryParseFunctionDeclarator() { if (TPR == TPResult::Ambiguous && Tok.isNot(tok::r_paren)) TPR = TPResult::False; - if (TPR == TPResult::False || TPR == TPResult::Error) - return TPR; + if (TPR != TPResult::Ambiguous) + if (VersusExpression || TPR != TPResult::True) + return TPR; // Parse through the parens. if (!SkipUntil(tok::r_paren, StopAtSemi)) diff --git a/clang/test/Parser/cxx-ambig-init-templ.cpp b/clang/test/Parser/cxx-ambig-init-templ.cpp index 1f692664137..584262c9be4 100644 --- a/clang/test/Parser/cxx-ambig-init-templ.cpp +++ b/clang/test/Parser/cxx-ambig-init-templ.cpp @@ -170,6 +170,15 @@ namespace ElaboratedTypeSpecifiers { }; } +namespace AbstractPtrOperatorDeclarator { + template <int, typename> struct X { + operator int(); + }; + struct Y { + void f(int a = X<0, int (*)()>()); + }; +} + namespace PR20459 { template <typename EncTraits> struct A { void foo(int = EncTraits::template TypeEnc<int, int>::val); // ok diff --git a/clang/test/Parser/cxx-variadic-func.cpp b/clang/test/Parser/cxx-variadic-func.cpp index 98a34d3e1bf..c0fad95e468 100644 --- a/clang/test/Parser/cxx-variadic-func.cpp +++ b/clang/test/Parser/cxx-variadic-func.cpp @@ -1,8 +1,7 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s void f(...) { - // FIXME: There's no disambiguation here; this is unambiguous. - int g(int(...)); // expected-warning {{disambiguated}} expected-note {{paren}} + int g(int(...)); // no warning, unambiguously a function declaration } void h(int n..., int m); // expected-error {{expected ')'}} expected-note {{to match}} diff --git a/clang/test/Parser/recovery.cpp b/clang/test/Parser/recovery.cpp index 2d5b518c691..f099473e04b 100644 --- a/clang/test/Parser/recovery.cpp +++ b/clang/test/Parser/recovery.cpp @@ -203,6 +203,14 @@ namespace pr15133 { }; } +namespace AbstractPtrOperator { + // A ptr-operator and no name means we have a declaration and not an + // expression. + template<typename T> int f(int*, T::type); // expected-error {{missing 'typename'}} + template<typename T> int f(int (T::*), T::type); // expected-error {{missing 'typename'}} + template<typename T> int f(int (*)(), T::type); // expected-error {{missing 'typename'}} +} + namespace InvalidEmptyNames { // These shouldn't crash, the diagnostics aren't important. struct ::, struct ::; // expected-error 2 {{expected identifier}} expected-error 2 {{declaration of anonymous struct must be a definition}} expected-warning {{declaration does not declare anything}} diff --git a/clang/test/SemaTemplate/rdar9173693.cpp b/clang/test/SemaTemplate/rdar9173693.cpp index 86b49545a30..1e999cba670 100644 --- a/clang/test/SemaTemplate/rdar9173693.cpp +++ b/clang/test/SemaTemplate/rdar9173693.cpp @@ -2,5 +2,5 @@ // <rdar://problem/9173693> template< bool C > struct assert { }; -template< bool > struct assert_arg_pred_impl { }; // expected-note 3 {{declared here}} -template< typename Pred > assert<false> assert_not_arg( void (*)(Pred), typename assert_arg_pred<Pred>::type ); // expected-error 5 {{}} +template< bool > struct assert_arg_pred_impl { }; // expected-note 2 {{declared here}} +template< typename Pred > assert<false> assert_not_arg( void (*)(Pred), typename assert_arg_pred<Pred>::type ); // expected-error 3 {{}} |