]> granicus.if.org Git - clang/commitdiff
Add missing direct-init / parameter-declaration-clause disambiguation when
authorRichard Smith <richard-llvm@metafoo.co.uk>
Fri, 2 Feb 2018 22:24:54 +0000 (22:24 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Fri, 2 Feb 2018 22:24:54 +0000 (22:24 +0000)
parsing a trailing-return-type of a (function pointer) variable declaration.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@324151 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Parse/Parser.h
include/clang/Sema/DeclSpec.h
lib/Parse/ParseDecl.cpp
lib/Parse/ParseDeclCXX.cpp
lib/Parse/ParseExprCXX.cpp
lib/Parse/ParseTentative.cpp
lib/Sema/SemaType.cpp
test/Parser/cxx-ambig-decl-expr.cpp
test/Parser/cxx0x-decl.cpp

index 6b722929f60c50a47be241ff5214d2ebdc9eeed3..93b9356e3a643eb378d0078161a66667de468ff5 100644 (file)
@@ -1644,7 +1644,8 @@ private:
 
   //===--------------------------------------------------------------------===//
   // C++0x 8: Function declaration trailing-return-type
-  TypeResult ParseTrailingReturnType(SourceRange &Range);
+  TypeResult ParseTrailingReturnType(SourceRange &Range,
+                                     bool MayBeFollowedByDirectInit);
 
   //===--------------------------------------------------------------------===//
   // C++ 2.13.5: C++ Boolean Literals
@@ -2158,7 +2159,8 @@ private:
   TPResult TryParsePtrOperatorSeq();
   TPResult TryParseOperatorId();
   TPResult TryParseInitDeclaratorList();
-  TPResult TryParseDeclarator(bool mayBeAbstract, bool mayHaveIdentifier=true);
+  TPResult TryParseDeclarator(bool mayBeAbstract, bool mayHaveIdentifier = true,
+                              bool mayHaveDirectInit = false);
   TPResult
   TryParseParameterDeclarationClause(bool *InvalidAsDeclaration = nullptr,
                                      bool VersusTemplateArg = false);
index 2e7411337bfcb73070a041c3d9c469f78e77112a..0baaa76f28612e1233f1da99fb6863b8db424997 100644 (file)
@@ -1731,6 +1731,7 @@ enum class DeclaratorContext {
     LambdaExprParameterContext, // Lambda-expression parameter declarator.
     ConversionIdContext, // C++ conversion-type-id.
     TrailingReturnContext, // C++11 trailing-type-specifier.
+    TrailingReturnVarContext, // C++11 trailing-type-specifier for variable.
     TemplateTypeArgContext, // Template type argument.
     AliasDeclContext,    // C++11 alias-declaration.
     AliasTemplateContext // C++11 alias-declaration template.
@@ -1950,6 +1951,7 @@ public:
     case DeclaratorContext::ConversionIdContext:
     case DeclaratorContext::TemplateTypeArgContext:
     case DeclaratorContext::TrailingReturnContext:
+    case DeclaratorContext::TrailingReturnVarContext:
       return true;
     }
     llvm_unreachable("unknown context kind!");
@@ -1986,6 +1988,7 @@ public:
     case DeclaratorContext::ConversionIdContext:
     case DeclaratorContext::TemplateTypeArgContext:
     case DeclaratorContext::TrailingReturnContext:
+    case DeclaratorContext::TrailingReturnVarContext:
       return false;
     }
     llvm_unreachable("unknown context kind!");
@@ -2026,6 +2029,7 @@ public:
     case DeclaratorContext::ConversionIdContext:
     case DeclaratorContext::TemplateTypeArgContext:
     case DeclaratorContext::TrailingReturnContext:
+    case DeclaratorContext::TrailingReturnVarContext:
       return false;
     }
     llvm_unreachable("unknown context kind!");
@@ -2052,6 +2056,7 @@ public:
     case DeclaratorContext::BlockContext:
     case DeclaratorContext::ForContext:
     case DeclaratorContext::InitStmtContext:
+    case DeclaratorContext::TrailingReturnVarContext:
       return true;
 
     case DeclaratorContext::ConditionContext:
@@ -2288,6 +2293,7 @@ public:
     case DeclaratorContext::ConversionIdContext:
     case DeclaratorContext::TemplateTypeArgContext:
     case DeclaratorContext::TrailingReturnContext:
+    case DeclaratorContext::TrailingReturnVarContext:
       return false;
     }
     llvm_unreachable("unknown context kind!");
@@ -2319,6 +2325,7 @@ public:
     case DeclaratorContext::LambdaExprContext:
     case DeclaratorContext::ConversionIdContext:
     case DeclaratorContext::TrailingReturnContext:
+    case DeclaratorContext::TrailingReturnVarContext:
       return false;
 
     case DeclaratorContext::BlockContext:
index 127e18439b8e01703b60320d7639ccaab3036abf..9e3e8ac0208e073941fba72446016bc03d9cd605 100644 (file)
@@ -2671,7 +2671,8 @@ Parser::getDeclSpecContextFromDeclaratorContext(DeclaratorContext Context) {
     return DeclSpecContext::DSC_template_param;
   if (Context == DeclaratorContext::TemplateTypeArgContext)
     return DeclSpecContext::DSC_template_type_arg;
-  if (Context == DeclaratorContext::TrailingReturnContext)
+  if (Context == DeclaratorContext::TrailingReturnContext ||
+      Context == DeclaratorContext::TrailingReturnVarContext)
     return DeclSpecContext::DSC_trailing;
   if (Context == DeclaratorContext::AliasDeclContext ||
       Context == DeclaratorContext::AliasTemplateContext)
@@ -5627,7 +5628,8 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
              D.getContext() == DeclaratorContext::AliasTemplateContext)
       // The most likely error is that the ';' was forgotten.
       DiagnoseIdentifier = NextToken().isOneOf(tok::comma, tok::semi);
-    else if (D.getContext() == DeclaratorContext::TrailingReturnContext &&
+    else if ((D.getContext() == DeclaratorContext::TrailingReturnContext ||
+              D.getContext() == DeclaratorContext::TrailingReturnVarContext) &&
              !isCXX11VirtSpecifier(Tok))
       DiagnoseIdentifier = NextToken().isOneOf(
           tok::comma, tok::semi, tok::equal, tok::l_brace, tok::kw_try);
@@ -5641,6 +5643,18 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
   }
 
   if (Tok.is(tok::l_paren)) {
+    // If this might be an abstract-declarator followed by a direct-initializer,
+    // check whether this is a valid declarator chunk. If it can't be, assume
+    // that it's an initializer instead.
+    if (D.mayOmitIdentifier() && D.mayBeFollowedByCXXDirectInit()) {
+      RevertingTentativeParsingAction PA(*this);
+      if (TryParseDeclarator(true, D.mayHaveIdentifier(), true) ==
+              TPResult::False) {
+        D.SetIdentifier(nullptr, Tok.getLocation());
+        goto PastIdentifier;
+      }
+    }
+
     // direct-declarator: '(' declarator ')'
     // direct-declarator: '(' attributes declarator ')'
     // Example: 'char (*X)'   or 'int (*XX)(void)'
@@ -6111,7 +6125,8 @@ void Parser::ParseFunctionDeclarator(Declarator &D,
           StartLoc = D.getDeclSpec().getTypeSpecTypeLoc();
         LocalEndLoc = Tok.getLocation();
         SourceRange Range;
-        TrailingReturnType = ParseTrailingReturnType(Range);
+        TrailingReturnType =
+            ParseTrailingReturnType(Range, D.mayBeFollowedByCXXDirectInit());
         EndLoc = Range.getEnd();
       }
     } else if (standardAttributesAllowed()) {
index 68b73ca1d25f294961a4754f576d57a442087279..172950fc673ad981f5972cab0c6c92f384c939ad 100644 (file)
@@ -3706,12 +3706,15 @@ ExceptionSpecificationType Parser::ParseDynamicExceptionSpecification(
 
 /// ParseTrailingReturnType - Parse a trailing return type on a new-style
 /// function declaration.
-TypeResult Parser::ParseTrailingReturnType(SourceRange &Range) {
+TypeResult Parser::ParseTrailingReturnType(SourceRange &Range,
+                                           bool MayBeFollowedByDirectInit) {
   assert(Tok.is(tok::arrow) && "expected arrow");
 
   ConsumeToken();
 
-  return ParseTypeName(&Range, DeclaratorContext::TrailingReturnContext);
+  return ParseTypeName(&Range, MayBeFollowedByDirectInit
+                                   ? DeclaratorContext::TrailingReturnVarContext
+                                   : DeclaratorContext::TrailingReturnContext);
 }
 
 /// \brief We have just started parsing the definition of a new class,
index 914f6f3613bbebec942ea62f33329ba91a37126c..ecb36fe668fe06cafe6cc5b2887323f967ad3150 100644 (file)
@@ -1183,7 +1183,8 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
     if (Tok.is(tok::arrow)) {
       FunLocalRangeEnd = Tok.getLocation();
       SourceRange Range;
-      TrailingReturnType = ParseTrailingReturnType(Range);
+      TrailingReturnType =
+          ParseTrailingReturnType(Range, /*MayBeFollowedByDirectInit*/ false);
       if (Range.getEnd().isValid())
         DeclEndLoc = Range.getEnd();
     }
@@ -1253,7 +1254,8 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
     // Parse the return type, if there is one.
     if (Tok.is(tok::arrow)) {
       SourceRange Range;
-      TrailingReturnType = ParseTrailingReturnType(Range);
+      TrailingReturnType =
+          ParseTrailingReturnType(Range, /*MayBeFollowedByDirectInit*/ false);
       if (Range.getEnd().isValid())
         DeclEndLoc = Range.getEnd();
     }
index 5c206f4eab90bd285922bd1730fbd1502cd8da0d..10c084b66dac49ad5ed1b82108a930542c7c3697 100644 (file)
@@ -873,7 +873,8 @@ Parser::TPResult Parser::TryParseOperatorId() {
 ///           template-id                                                 [TODO]
 ///
 Parser::TPResult Parser::TryParseDeclarator(bool mayBeAbstract,
-                                            bool mayHaveIdentifier) {
+                                            bool mayHaveIdentifier,
+                                            bool mayHaveDirectInit) {
   // declarator:
   //   direct-declarator
   //   ptr-operator declarator
@@ -930,6 +931,9 @@ Parser::TPResult Parser::TryParseDeclarator(bool mayBeAbstract,
     return TPResult::False;
   }
 
+  if (mayHaveDirectInit)
+    return TPResult::Ambiguous;
+
   while (1) {
     TPResult TPR(TPResult::Ambiguous);
 
index af060cf21b5fa4a92c8d3a3c6b7c42de62fab6b4..6984505d98f072ef0a0ca16358af894d07e413c0 100644 (file)
@@ -2859,6 +2859,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
       Error = 12; // Type alias
       break;
     case DeclaratorContext::TrailingReturnContext:
+    case DeclaratorContext::TrailingReturnVarContext:
       if (!SemaRef.getLangOpts().CPlusPlus14 || !IsCXXAutoType)
         Error = 13; // Function return type
       break;
@@ -2961,6 +2962,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
     unsigned DiagID = 0;
     switch (D.getContext()) {
     case DeclaratorContext::TrailingReturnContext:
+    case DeclaratorContext::TrailingReturnVarContext:
       // Class and enumeration definitions are syntactically not allowed in
       // trailing return types.
       llvm_unreachable("parser should not have allowed this");
@@ -3914,6 +3916,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
     case DeclaratorContext::ObjCResultContext:
     case DeclaratorContext::PrototypeContext:
     case DeclaratorContext::TrailingReturnContext:
+    case DeclaratorContext::TrailingReturnVarContext:
       isFunctionOrMethod = true;
       LLVM_FALLTHROUGH;
 
@@ -4954,6 +4957,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
     case DeclaratorContext::LambdaExprContext:
     case DeclaratorContext::ConversionIdContext:
     case DeclaratorContext::TrailingReturnContext:
+    case DeclaratorContext::TrailingReturnVarContext:
     case DeclaratorContext::TemplateTypeArgContext:
       // FIXME: We may want to allow parameter packs in block-literal contexts
       // in the future.
index feb185fbe3f282b8d23b599cfce29782b3822686..7bf08b02c4f59780f7ae127b4a9873927e25171b 100644 (file)
@@ -11,3 +11,7 @@ void f() {
   unknown *p = 0; // expected-error {{unknown type name 'unknown'}}
   unknown * p + 0; // expected-error {{undeclared identifier 'unknown'}}
 }
+
+auto (*p)() -> int(nullptr);
+auto (*q)() -> int(*)(unknown); // expected-error {{unknown type name 'unknown'}}
+auto (*r)() -> int(*)(unknown + 1); // expected-error {{undeclared identifier 'unknown'}}
index 2b253c019c971eed20caaa9b3aaaaf7e4a17d57a..1eaf84a471e24d12e6fffc17fdef6d067eb66fb0 100644 (file)
@@ -79,7 +79,7 @@ enum E
 namespace PR5066 {
   using T = int (*f)(); // expected-error {{type-id cannot have a name}}
   template<typename T> using U = int (*f)(); // expected-error {{type-id cannot have a name}}
-  auto f() -> int (*f)(); // expected-error {{type-id cannot have a name}}
+  auto f() -> int (*f)(); // expected-error {{only variables can be initialized}} expected-error {{expected ';'}}
   auto g = []() -> int (*f)() {}; // expected-error {{type-id cannot have a name}}
 }