Remove redundant CXXScopeSpec from TemplateIdAnnotation.
authorRichard Smith <richard@metafoo.co.uk>
Fri, 17 Jan 2020 23:42:11 +0000 (15:42 -0800)
committerRichard Smith <richard@metafoo.co.uk>
Fri, 17 Jan 2020 23:47:21 +0000 (15:47 -0800)
A TemplateIdAnnotation represents only a template-id, not a
nested-name-specifier plus a template-id. Don't make a redundant copy of
the CXXScopeSpec and store it on the template-id annotation.

This slightly improves error recovery by more properly handling the case
where we would form an invalid CXXScopeSpec while parsing a typename
specifier, instead of accidentally putting the token stream into a
broken "annot_template_id with a scope specifier, but with no preceding
annot_cxxscope token" state.

16 files changed:
clang/include/clang/Parse/Parser.h
clang/include/clang/Sema/ParsedTemplate.h
clang/include/clang/Sema/Sema.h
clang/lib/Parse/ParseDecl.cpp
clang/lib/Parse/ParseDeclCXX.cpp
clang/lib/Parse/ParseExpr.cpp
clang/lib/Parse/ParseExprCXX.cpp
clang/lib/Parse/ParseTemplate.cpp
clang/lib/Parse/ParseTentative.cpp
clang/lib/Parse/Parser.cpp
clang/lib/Sema/SemaExprCXX.cpp
clang/lib/Sema/SemaTemplate.cpp
clang/test/CXX/temp/temp.res/temp.dep/temp.dep.constexpr/p2.cpp
clang/test/Parser/cxx-decl.cpp
clang/test/SemaTemplate/ms-delayed-default-template-args.cpp
clang/test/SemaTemplate/rdar9173693.cpp

index b7bed47..182024e 100644 (file)
@@ -3079,13 +3079,13 @@ private:
                                SourceLocation &RAngleLoc);
   bool ParseTemplateParameterList(unsigned Depth,
                                   SmallVectorImpl<NamedDecl*> &TemplateParams);
-  bool isStartOfTemplateTypeParameter(bool &ScopeError);
+  TPResult isStartOfTemplateTypeParameter();
   NamedDecl *ParseTemplateParameter(unsigned Depth, unsigned Position);
   NamedDecl *ParseTypeParameter(unsigned Depth, unsigned Position);
   NamedDecl *ParseTemplateTemplateParameter(unsigned Depth, unsigned Position);
   NamedDecl *ParseNonTypeTemplateParameter(unsigned Depth, unsigned Position);
   bool isTypeConstraintAnnotation();
-  bool TryAnnotateTypeConstraint(CXXScopeSpec &SS);
+  bool TryAnnotateTypeConstraint();
   NamedDecl *
   ParseConstrainedTemplateTypeParameter(unsigned Depth, unsigned Position);
   void DiagnoseMisplacedEllipsis(SourceLocation EllipsisLoc,
@@ -3111,7 +3111,8 @@ private:
                                UnqualifiedId &TemplateName,
                                bool AllowTypeAnnotation = true,
                                bool TypeConstraint = false);
-  void AnnotateTemplateIdTokenAsType(bool IsClassName = false);
+  void AnnotateTemplateIdTokenAsType(CXXScopeSpec &SS,
+                                     bool IsClassName = false);
   bool ParseTemplateArgumentList(TemplateArgList &TemplateArgs);
   ParsedTemplateArgument ParseTemplateTemplateArgument();
   ParsedTemplateArgument ParseTemplateArgument();
index 0874905..82d0049 100644 (file)
@@ -139,9 +139,8 @@ namespace clang {
   /// Information about a template-id annotation
   /// token.
   ///
-  /// A template-id annotation token contains the template declaration,
-  /// template arguments, whether those template arguments were types,
-  /// expressions, or template names, and the source locations for important
+  /// A template-id annotation token contains the template name,
+  /// template arguments, and the source locations for important
   /// tokens. All of the information about template arguments is allocated
   /// directly after this structure.
   /// A template-id annotation token can also be generated by a type-constraint
@@ -152,9 +151,6 @@ namespace clang {
       : private llvm::TrailingObjects<TemplateIdAnnotation,
                                       ParsedTemplateArgument> {
     friend TrailingObjects;
-    /// The nested-name-specifier that precedes the template name.
-    CXXScopeSpec SS;
-
     /// TemplateKWLoc - The location of the template keyword.
     /// For e.g. typename T::template Y<U>
     SourceLocation TemplateKWLoc;
@@ -195,16 +191,15 @@ namespace clang {
     /// Creates a new TemplateIdAnnotation with NumArgs arguments and
     /// appends it to List.
     static TemplateIdAnnotation *
-    Create(CXXScopeSpec SS, SourceLocation TemplateKWLoc,
-           SourceLocation TemplateNameLoc, IdentifierInfo *Name,
-           OverloadedOperatorKind OperatorKind,
+    Create(SourceLocation TemplateKWLoc, SourceLocation TemplateNameLoc,
+           IdentifierInfo *Name, OverloadedOperatorKind OperatorKind,
            ParsedTemplateTy OpaqueTemplateName, TemplateNameKind TemplateKind,
            SourceLocation LAngleLoc, SourceLocation RAngleLoc,
            ArrayRef<ParsedTemplateArgument> TemplateArgs,
            SmallVectorImpl<TemplateIdAnnotation *> &CleanupList) {
       TemplateIdAnnotation *TemplateId = new (llvm::safe_malloc(
           totalSizeToAlloc<ParsedTemplateArgument>(TemplateArgs.size())))
-          TemplateIdAnnotation(SS, TemplateKWLoc, TemplateNameLoc, Name,
+          TemplateIdAnnotation(TemplateKWLoc, TemplateNameLoc, Name,
                                OperatorKind, OpaqueTemplateName, TemplateKind,
                                LAngleLoc, RAngleLoc, TemplateArgs);
       CleanupList.push_back(TemplateId);
@@ -221,17 +216,16 @@ namespace clang {
   private:
     TemplateIdAnnotation(const TemplateIdAnnotation &) = delete;
 
-    TemplateIdAnnotation(CXXScopeSpec SS, SourceLocation TemplateKWLoc,
+    TemplateIdAnnotation(SourceLocation TemplateKWLoc,
                          SourceLocation TemplateNameLoc, IdentifierInfo *Name,
                          OverloadedOperatorKind OperatorKind,
                          ParsedTemplateTy OpaqueTemplateName,
                          TemplateNameKind TemplateKind,
                          SourceLocation LAngleLoc, SourceLocation RAngleLoc,
                          ArrayRef<ParsedTemplateArgument> TemplateArgs) noexcept
-        : SS(SS), TemplateKWLoc(TemplateKWLoc),
-          TemplateNameLoc(TemplateNameLoc), Name(Name), Operator(OperatorKind),
-          Template(OpaqueTemplateName), Kind(TemplateKind),
-          LAngleLoc(LAngleLoc), RAngleLoc(RAngleLoc),
+        : TemplateKWLoc(TemplateKWLoc), TemplateNameLoc(TemplateNameLoc),
+          Name(Name), Operator(OperatorKind), Template(OpaqueTemplateName),
+          Kind(TemplateKind), LAngleLoc(LAngleLoc), RAngleLoc(RAngleLoc),
           NumArgs(TemplateArgs.size()) {
 
       std::uninitialized_copy(TemplateArgs.begin(), TemplateArgs.end(),
index 9c38cdc..4d76c87 100644 (file)
@@ -6873,7 +6873,8 @@ public:
                                 SourceLocation EqualLoc,
                                 ParsedType DefaultArg, bool HasTypeConstraint);
 
-  bool ActOnTypeConstraint(TemplateIdAnnotation *TypeConstraint,
+  bool ActOnTypeConstraint(const CXXScopeSpec &SS,
+                           TemplateIdAnnotation *TypeConstraint,
                            TemplateTypeParmDecl *ConstrainedParameter,
                            SourceLocation EllipsisLoc);
 
@@ -7028,8 +7029,8 @@ public:
 
   DeclResult ActOnClassTemplateSpecialization(
       Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc,
-      SourceLocation ModulePrivateLoc, TemplateIdAnnotation &TemplateId,
-      const ParsedAttributesView &Attr,
+      SourceLocation ModulePrivateLoc, CXXScopeSpec &SS,
+      TemplateIdAnnotation &TemplateId, const ParsedAttributesView &Attr,
       MultiTemplateParamsArg TemplateParameterLists,
       SkipBodyInfo *SkipBody = nullptr);
 
index d8c5a0a..192c0e9 100644 (file)
@@ -3177,7 +3177,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
              DSContext == DeclSpecContext::DSC_class) &&
             TemplateId->Name &&
             Actions.isCurrentClassName(*TemplateId->Name, getCurScope(), &SS) &&
-            isConstructorDeclarator(/*Unqualified*/ false)) {
+            isConstructorDeclarator(/*Unqualified=*/false)) {
           // The user meant this to be an out-of-line constructor
           // definition, but template arguments are not allowed
           // there.  Just allow this as a constructor; we'll
@@ -3189,7 +3189,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
         ConsumeAnnotationToken(); // The C++ scope.
         assert(Tok.is(tok::annot_template_id) &&
                "ParseOptionalCXXScopeSpecifier not working");
-        AnnotateTemplateIdTokenAsType();
+        AnnotateTemplateIdTokenAsType(SS);
         continue;
       }
 
@@ -3448,12 +3448,13 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
       // constructor declaration.
       if (getLangOpts().CPlusPlus && DSContext == DeclSpecContext::DSC_class &&
           Actions.isCurrentClassName(*TemplateId->Name, getCurScope()) &&
-          isConstructorDeclarator(TemplateId->SS.isEmpty()))
+          isConstructorDeclarator(/*Unqualified=*/true))
         goto DoneWithDeclSpec;
 
       // Turn the template-id annotation token into a type annotation
       // token, then try again to parse it as a type-specifier.
-      AnnotateTemplateIdTokenAsType();
+      CXXScopeSpec SS;
+      AnnotateTemplateIdTokenAsType(SS);
       continue;
     }
 
index 081d4d8..9c7d3c5 100644 (file)
@@ -1142,7 +1142,7 @@ TypeResult Parser::ParseBaseTypeSpecifier(SourceLocation &BaseLoc,
     if (TemplateId->Kind == TNK_Type_template ||
         TemplateId->Kind == TNK_Dependent_template_name ||
         TemplateId->Kind == TNK_Undeclared_template) {
-      AnnotateTemplateIdTokenAsType(/*IsClassName*/true);
+      AnnotateTemplateIdTokenAsType(SS, /*IsClassName*/true);
 
       assert(Tok.is(tok::annot_typename) && "template-id -> type failed");
       ParsedType Type = getTypeAnnotation(Tok);
@@ -1193,7 +1193,7 @@ TypeResult Parser::ParseBaseTypeSpecifier(SourceLocation &BaseLoc,
                                 TemplateName))
       return true;
     if (TNK == TNK_Type_template || TNK == TNK_Dependent_template_name)
-      AnnotateTemplateIdTokenAsType(/*IsClassName*/true);
+      AnnotateTemplateIdTokenAsType(SS, /*IsClassName*/true);
 
     // If we didn't end up with a typename token, there's nothing more we
     // can do.
@@ -1826,7 +1826,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
                 TemplateInfo.Kind == ParsedTemplateInfo::NonTemplate)) {
       ProhibitAttributes(attrs);
       TypeResult = Actions.ActOnTagTemplateIdType(TUK, TagType, StartLoc,
-                                                  TemplateId->SS,
+                                                  SS,
                                                   TemplateId->TemplateKWLoc,
                                                   TemplateId->Template,
                                                   TemplateId->TemplateNameLoc,
@@ -1876,7 +1876,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
       // Build the class template specialization.
       TagOrTempResult = Actions.ActOnClassTemplateSpecialization(
           getCurScope(), TagType, TUK, StartLoc, DS.getModulePrivateSpecLoc(),
-          *TemplateId, attrs,
+          SS, *TemplateId, attrs,
           MultiTemplateParamsArg(TemplateParams ? &(*TemplateParams)[0]
                                                 : nullptr,
                                  TemplateParams ? TemplateParams->size() : 0),
@@ -3520,7 +3520,7 @@ MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) {
     if (TemplateId && (TemplateId->Kind == TNK_Type_template ||
                        TemplateId->Kind == TNK_Dependent_template_name ||
                        TemplateId->Kind == TNK_Undeclared_template)) {
-      AnnotateTemplateIdTokenAsType(/*IsClassName*/true);
+      AnnotateTemplateIdTokenAsType(SS, /*IsClassName*/true);
       assert(Tok.is(tok::annot_typename) && "template-id -> type failed");
       TemplateTypeTy = getTypeAnnotation(Tok);
       ConsumeAnnotationToken();
index 1442df0..32dacbc 100644 (file)
@@ -1530,7 +1530,7 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind,
         CXXScopeSpec SS;
         ParseOptionalCXXScopeSpecifier(SS, nullptr,
                                        /*EnteringContext=*/false);
-        AnnotateTemplateIdTokenAsType();
+        AnnotateTemplateIdTokenAsType(SS);
         return ParseCastExpression(ParseKind, isAddressOfOperand, NotCastExpr,
                                    isTypeCast, isVectorLiteral,
                                    NotPrimaryExpression);
@@ -1548,7 +1548,8 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind,
       // We have a template-id that we know refers to a type,
       // translate it into a type and continue parsing as a cast
       // expression.
-      AnnotateTemplateIdTokenAsType();
+      CXXScopeSpec SS;
+      AnnotateTemplateIdTokenAsType(SS);
       return ParseCastExpression(ParseKind, isAddressOfOperand,
                                  NotCastExpr, isTypeCast, isVectorLiteral,
                                  NotPrimaryExpression);
index e685d5e..7d477d2 100644 (file)
@@ -165,13 +165,6 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
     return false;
   }
 
-  if (Tok.is(tok::annot_template_id)) {
-    // If the current token is an annotated template id, it may already have
-    // a scope specifier. Restore it.
-    TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok);
-    SS = TemplateId->SS;
-  }
-
   // Has to happen before any "return false"s in this function.
   bool CheckForDestructor = false;
   if (MayBePseudoDestructor && *MayBePseudoDestructor) {
@@ -2405,7 +2398,7 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS,
             : Id.OperatorFunctionId.Operator;
 
     TemplateIdAnnotation *TemplateId = TemplateIdAnnotation::Create(
-        SS, TemplateKWLoc, Id.StartLocation, TemplateII, OpKind, Template, TNK,
+        TemplateKWLoc, Id.StartLocation, TemplateII, OpKind, Template, TNK,
         LAngleLoc, RAngleLoc, TemplateArgs, TemplateIds);
 
     Id.setTemplateId(TemplateId);
index 1b9301b..0f7aefa 100644 (file)
@@ -499,10 +499,7 @@ Parser::ParseTemplateParameterList(const unsigned Depth,
 
 /// Determine whether the parser is at the start of a template
 /// type parameter.
-/// \param ScopeError will receive true if there was an error parsing a
-/// scope specifier at the current location.
-bool Parser::isStartOfTemplateTypeParameter(bool &ScopeError) {
-  ScopeError = false;
+Parser::TPResult Parser::isStartOfTemplateTypeParameter() {
   if (Tok.is(tok::kw_class)) {
     // "class" may be the start of an elaborated-type-specifier or a
     // type-parameter. Per C++ [temp.param]p3, we prefer the type-parameter.
@@ -512,7 +509,7 @@ bool Parser::isStartOfTemplateTypeParameter(bool &ScopeError) {
     case tok::greater:
     case tok::greatergreater:
     case tok::ellipsis:
-      return true;
+      return TPResult::True;
 
     case tok::identifier:
       // This may be either a type-parameter or an elaborated-type-specifier.
@@ -520,7 +517,7 @@ bool Parser::isStartOfTemplateTypeParameter(bool &ScopeError) {
       break;
 
     default:
-      return false;
+      return TPResult::False;
     }
 
     switch (GetLookAheadToken(2).getKind()) {
@@ -528,51 +525,28 @@ bool Parser::isStartOfTemplateTypeParameter(bool &ScopeError) {
     case tok::comma:
     case tok::greater:
     case tok::greatergreater:
-      return true;
+      return TPResult::True;
 
     default:
-      return false;
+      return TPResult::False;
     }
   }
 
-  bool WasScopeAnnotation = Tok.is(tok::annot_cxxscope);
-  CXXScopeSpec SS;
-  ScopeError =
-      ParseOptionalCXXScopeSpecifier(SS, ParsedType(),
-                                     /*EnteringContext=*/false,
-                                     /*MayBePseudoDestructor=*/nullptr,
-                                     // If this is not a type-constraint, then
-                                     // this scope-spec is part of the typename
-                                     // of a non-type template parameter
-                                     /*IsTypename=*/true, /*LastII=*/nullptr,
-                                     // We won't find concepts in
-                                     // non-namespaces anyway, so might as well
-                                     // parse this correctly for possible type
-                                     // names.
-                                     /*OnlyNamespace=*/false);
-  if (ScopeError)
-    return false;
-  if (TryAnnotateTypeConstraint(SS))
-    return false;
-  bool IsTypeConstraint = isTypeConstraintAnnotation();
-  if (!IsTypeConstraint && SS.isNotEmpty()) {
-    // This isn't a type-constraint but we've already parsed this scope
-    // specifier - annotate it.
-    AnnotateScopeToken(SS, /*isNewAnnotation=*/!WasScopeAnnotation);
-    return false;
-  }
+  if (TryAnnotateTypeConstraint())
+    return TPResult::Error;
 
-  if (IsTypeConstraint &&
+  if (isTypeConstraintAnnotation() &&
       // Next token might be 'auto' or 'decltype', indicating that this
       // type-constraint is in fact part of a placeholder-type-specifier of a
       // non-type template parameter.
-      !NextToken().isOneOf(tok::kw_auto, tok::kw_decltype))
-    return true;
+      !GetLookAheadToken(Tok.is(tok::annot_cxxscope) ? 2 : 1)
+           .isOneOf(tok::kw_auto, tok::kw_decltype))
+    return TPResult::True;
 
   // 'typedef' is a reasonably-common typo/thinko for 'typename', and is
   // ill-formed otherwise.
   if (Tok.isNot(tok::kw_typename) && Tok.isNot(tok::kw_typedef))
-    return false;
+    return TPResult::False;
 
   // C++ [temp.param]p2:
   //   There is no semantic difference between class and typename in a
@@ -592,17 +566,17 @@ bool Parser::isStartOfTemplateTypeParameter(bool &ScopeError) {
   case tok::greater:
   case tok::greatergreater:
   case tok::ellipsis:
-    return true;
+    return TPResult::True;
 
   case tok::kw_typename:
   case tok::kw_typedef:
   case tok::kw_class:
     // These indicate that a comma was missed after a type parameter, not that
     // we have found a non-type parameter.
-    return true;
+    return TPResult::True;
 
   default:
-    return false;
+    return TPResult::False;
   }
 }
 
@@ -627,13 +601,8 @@ bool Parser::isStartOfTemplateTypeParameter(bool &ScopeError) {
 ///         typename
 ///
 NamedDecl *Parser::ParseTemplateParameter(unsigned Depth, unsigned Position) {
-  // We could be facing a type-constraint, which (could) start a type parameter.
-  // Annotate it now (we might end up not using it if we determine this
-  // type-constraint is in fact part of a placeholder-type-specifier of a
-  // non-type template parameter.
-
-  bool ScopeError;
-  if (isStartOfTemplateTypeParameter(ScopeError)) {
+  switch (isStartOfTemplateTypeParameter()) {
+  case TPResult::True:
     // Is there just a typo in the input code? ('typedef' instead of
     // 'typename')
     if (Tok.is(tok::kw_typedef)) {
@@ -649,8 +618,11 @@ NamedDecl *Parser::ParseTemplateParameter(unsigned Depth, unsigned Position) {
     }
 
     return ParseTypeParameter(Depth, Position);
-  }
-  if (ScopeError) {
+
+  case TPResult::False:
+    break;
+
+  case TPResult::Error: {
     // We return an invalid parameter as opposed to null to avoid having bogus
     // diagnostics about an empty template parameter list.
     // FIXME: Fix ParseTemplateParameterList to better handle nullptr results
@@ -670,6 +642,11 @@ NamedDecl *Parser::ParseTemplateParameter(unsigned Depth, unsigned Position) {
               StopAtSemi | StopBeforeMatch);
     return ErrorParam;
   }
+
+  case TPResult::Ambiguous:
+    llvm_unreachable("template param classification can't be ambiguous");
+  }
+
   if (Tok.is(tok::kw_template))
     return ParseTemplateTemplateParameter(Depth, Position);
 
@@ -682,15 +659,15 @@ NamedDecl *Parser::ParseTemplateParameter(unsigned Depth, unsigned Position) {
 /// Check whether the current token is a template-id annotation denoting a
 /// type-constraint.
 bool Parser::isTypeConstraintAnnotation() {
-  if (Tok.isNot(tok::annot_template_id))
+  const Token &T = Tok.is(tok::annot_cxxscope) ? NextToken() : Tok;
+  if (T.isNot(tok::annot_template_id))
     return false;
   const auto *ExistingAnnot =
-      static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
+      static_cast<TemplateIdAnnotation *>(T.getAnnotationValue());
   return ExistingAnnot->Kind == TNK_Concept_template;
 }
 
-/// Try parsing a type-constraint construct at the current location, after the
-/// optional scope specifier.
+/// Try parsing a type-constraint at the current location.
 ///
 ///     type-constraint:
 ///       nested-name-specifier[opt] concept-name
@@ -698,35 +675,60 @@ bool Parser::isTypeConstraintAnnotation() {
 ///           '<' template-argument-list[opt] '>'[opt]
 ///
 /// \returns true if an error occurred, and false otherwise.
-bool Parser::TryAnnotateTypeConstraint(CXXScopeSpec &SS) {
-  if (!getLangOpts().ConceptsTS || Tok.isNot(tok::identifier))
+bool Parser::TryAnnotateTypeConstraint() {
+  if (!getLangOpts().ConceptsTS)
     return false;
 
-  UnqualifiedId PossibleConceptName;
-  PossibleConceptName.setIdentifier(Tok.getIdentifierInfo(),
-                                    Tok.getLocation());
-
-  TemplateTy PossibleConcept;
-  bool MemberOfUnknownSpecialization = false;
-  auto TNK = Actions.isTemplateName(getCurScope(), SS,
-                                    /*hasTemplateKeyword=*/false,
-                                    PossibleConceptName,
-                                    /*ObjectType=*/ParsedType(),
-                                    /*EnteringContext=*/false,
-                                    PossibleConcept,
-                                    MemberOfUnknownSpecialization);
-  assert(!MemberOfUnknownSpecialization
-         && "Member when we only allowed namespace scope qualifiers??");
-  if (!PossibleConcept || TNK != TNK_Concept_template)
-    return false;
+  CXXScopeSpec SS;
+  bool WasScopeAnnotation = Tok.is(tok::annot_cxxscope);
+  if (ParseOptionalCXXScopeSpecifier(
+          SS, ParsedType(),
+          /*EnteringContext=*/false,
+          /*MayBePseudoDestructor=*/nullptr,
+          // If this is not a type-constraint, then
+          // this scope-spec is part of the typename
+          // of a non-type template parameter
+          /*IsTypename=*/true, /*LastII=*/nullptr,
+          // We won't find concepts in
+          // non-namespaces anyway, so might as well
+          // parse this correctly for possible type
+          // names.
+          /*OnlyNamespace=*/false))
+    return true;
 
-  // At this point we're sure we're dealing with a constrained parameter. It
-  // may or may not have a template parameter list following the concept name.
-  return AnnotateTemplateIdToken(PossibleConcept, TNK, SS,
-                                 /*TemplateKWLoc=*/SourceLocation(),
-                                 PossibleConceptName,
-                                 /*AllowTypeAnnotation=*/false,
-                                 /*TypeConstraint=*/true);
+  if (Tok.is(tok::identifier)) {
+    UnqualifiedId PossibleConceptName;
+    PossibleConceptName.setIdentifier(Tok.getIdentifierInfo(),
+                                      Tok.getLocation());
+
+    TemplateTy PossibleConcept;
+    bool MemberOfUnknownSpecialization = false;
+    auto TNK = Actions.isTemplateName(getCurScope(), SS,
+                                      /*hasTemplateKeyword=*/false,
+                                      PossibleConceptName,
+                                      /*ObjectType=*/ParsedType(),
+                                      /*EnteringContext=*/false,
+                                      PossibleConcept,
+                                      MemberOfUnknownSpecialization);
+    assert(!MemberOfUnknownSpecialization
+           && "Member when we only allowed namespace scope qualifiers??");
+    if (!PossibleConcept || TNK != TNK_Concept_template)
+      return false;
+
+    // At this point we're sure we're dealing with a constrained parameter. It
+    // may or may not have a template parameter list following the concept
+    // name.
+    if (AnnotateTemplateIdToken(PossibleConcept, TNK, SS,
+                                   /*TemplateKWLoc=*/SourceLocation(),
+                                   PossibleConceptName,
+                                   /*AllowTypeAnnotation=*/false,
+                                   /*TypeConstraint=*/true))
+      return true;
+  }
+
+  if (SS.isNotEmpty())
+    AnnotateScopeToken(SS, !WasScopeAnnotation);
+  return false;
 }
 
 /// ParseTypeParameter - Parse a template type parameter (C++ [temp.param]).
@@ -739,13 +741,17 @@ bool Parser::TryAnnotateTypeConstraint(CXXScopeSpec &SS) {
 ///         'typename' ...[opt][C++0x] identifier[opt]
 ///         'typename' identifier[opt] '=' type-id
 NamedDecl *Parser::ParseTypeParameter(unsigned Depth, unsigned Position) {
-  assert(Tok.isOneOf(tok::kw_class, tok::kw_typename, tok::annot_template_id) &&
+  assert((Tok.isOneOf(tok::kw_class, tok::kw_typename) ||
+          isTypeConstraintAnnotation()) &&
          "A type-parameter starts with 'class', 'typename' or a "
          "type-constraint");
 
+  CXXScopeSpec TypeConstraintSS;
   TemplateIdAnnotation *TypeConstraint = nullptr;
   bool TypenameKeyword = false;
   SourceLocation KeyLoc;
+  ParseOptionalCXXScopeSpecifier(TypeConstraintSS, nullptr,
+                                 /*EnteringContext*/ false);
   if (Tok.is(tok::annot_template_id)) {
     // Consume the 'type-constraint'.
     TypeConstraint =
@@ -754,6 +760,9 @@ NamedDecl *Parser::ParseTypeParameter(unsigned Depth, unsigned Position) {
            "stray non-concept template-id annotation");
     KeyLoc = ConsumeAnnotationToken();
   } else {
+    assert(TypeConstraintSS.isEmpty() &&
+           "expected type constraint after scope specifier");
+
     // Consume the 'class' or 'typename' keyword.
     TypenameKeyword = Tok.is(tok::kw_typename);
     KeyLoc = ConsumeToken();
@@ -795,7 +804,8 @@ NamedDecl *Parser::ParseTypeParameter(unsigned Depth, unsigned Position) {
   ParsedType DefaultArg;
   if (TryConsumeToken(tok::equal, EqualLoc))
     DefaultArg = ParseTypeName(/*Range=*/nullptr,
-                               DeclaratorContext::TemplateTypeArgContext).get();
+                               DeclaratorContext::TemplateTypeArgContext)
+                     .get();
 
   NamedDecl *NewDecl = Actions.ActOnTypeParameter(getCurScope(),
                                                   TypenameKeyword, EllipsisLoc,
@@ -804,10 +814,11 @@ NamedDecl *Parser::ParseTypeParameter(unsigned Depth, unsigned Position) {
                                                   DefaultArg,
                                                   TypeConstraint != nullptr);
 
-  if (TypeConstraint)
-    Actions.ActOnTypeConstraint(TypeConstraint,
+  if (TypeConstraint) {
+    Actions.ActOnTypeConstraint(TypeConstraintSS, TypeConstraint,
                                 cast<TemplateTypeParmDecl>(NewDecl),
                                 EllipsisLoc);
+  }
 
   return NewDecl;
 }
@@ -1331,8 +1342,8 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK,
             : TemplateName.OperatorFunctionId.Operator;
 
     TemplateIdAnnotation *TemplateId = TemplateIdAnnotation::Create(
-      SS, TemplateKWLoc, TemplateNameLoc, TemplateII, OpKind, Template, TNK,
-      LAngleLoc, RAngleLoc, TemplateArgs, TemplateIds);
+        TemplateKWLoc, TemplateNameLoc, TemplateII, OpKind, Template, TNK,
+        LAngleLoc, RAngleLoc, TemplateArgs, TemplateIds);
 
     Tok.setAnnotationValue(TemplateId);
     if (TemplateKWLoc.isValid())
@@ -1357,11 +1368,14 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK,
 /// a type annotation token will still be created, but will have a
 /// NULL type pointer to signify an error.
 ///
+/// \param SS The scope specifier appearing before the template-id, if any.
+///
 /// \param IsClassName Is this template-id appearing in a context where we
 /// know it names a class, such as in an elaborated-type-specifier or
 /// base-specifier? ('typename' and 'template' are unneeded and disallowed
 /// in those contexts.)
-void Parser::AnnotateTemplateIdTokenAsType(bool IsClassName) {
+void Parser::AnnotateTemplateIdTokenAsType(CXXScopeSpec &SS,
+                                           bool IsClassName) {
   assert(Tok.is(tok::annot_template_id) && "Requires template-id tokens");
 
   TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok);
@@ -1375,7 +1389,7 @@ void Parser::AnnotateTemplateIdTokenAsType(bool IsClassName) {
 
   TypeResult Type
     = Actions.ActOnTemplateIdType(getCurScope(),
-                                  TemplateId->SS,
+                                  SS,
                                   TemplateId->TemplateKWLoc,
                                   TemplateId->Template,
                                   TemplateId->Name,
@@ -1388,8 +1402,8 @@ void Parser::AnnotateTemplateIdTokenAsType(bool IsClassName) {
   // Create the new "type" annotation token.
   Tok.setKind(tok::annot_typename);
   setTypeAnnotation(Tok, Type.isInvalid() ? nullptr : Type.get());
-  if (TemplateId->SS.isNotEmpty()) // it was a C++ qualified type name.
-    Tok.setLocation(TemplateId->SS.getBeginLoc());
+  if (SS.isNotEmpty()) // it was a C++ qualified type name.
+    Tok.setLocation(SS.getBeginLoc());
   // End location stays the same
 
   // Replace the template-id annotation token, and possible the scope-specifier
index d5068fb..79e9681 100644 (file)
@@ -1519,7 +1519,7 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult,
     if (TemplateId->Kind != TNK_Type_template)
       return TPResult::False;
     CXXScopeSpec SS;
-    AnnotateTemplateIdTokenAsType();
+    AnnotateTemplateIdTokenAsType(SS);
     assert(Tok.is(tok::annot_typename));
     goto case_typename;
   }
index 0fb0a52..0194c24 100644 (file)
@@ -1810,7 +1810,7 @@ bool Parser::TryAnnotateTypeOrScopeToken() {
                                        /*EnteringContext=*/false, nullptr,
                                        /*IsTypename*/ true))
       return true;
-    if (!SS.isSet()) {
+    if (SS.isEmpty()) {
       if (Tok.is(tok::identifier) || Tok.is(tok::annot_template_id) ||
           Tok.is(tok::annot_decltype)) {
         // Attempt to recover by skipping the invalid 'typename'
@@ -1983,7 +1983,7 @@ bool Parser::TryAnnotateTypeOrScopeTokenAfterScopeSpec(CXXScopeSpec &SS,
       // template-id annotation in a context where we weren't allowed
       // to produce a type annotation token. Update the template-id
       // annotation token to a type annotation token now.
-      AnnotateTemplateIdTokenAsType();
+      AnnotateTemplateIdTokenAsType(SS);
       return false;
     }
   }
index a73e690..938420d 100644 (file)
@@ -7317,7 +7317,7 @@ ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base,
     ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(),
                                        TemplateId->NumArgs);
     TypeResult T = ActOnTemplateIdType(S,
-                                       TemplateId->SS,
+                                       SS,
                                        TemplateId->TemplateKWLoc,
                                        TemplateId->Template,
                                        TemplateId->Name,
@@ -7370,7 +7370,7 @@ ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base,
       ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(),
                                          TemplateId->NumArgs);
       TypeResult T = ActOnTemplateIdType(S,
-                                         TemplateId->SS,
+                                         SS,
                                          TemplateId->TemplateKWLoc,
                                          TemplateId->Template,
                                          TemplateId->Name,
index 1184446..8a50a9e 100755 (executable)
@@ -1050,7 +1050,8 @@ makeTemplateArgumentListInfo(Sema &S, TemplateIdAnnotation &TemplateId) {
   return TemplateArgs;
 }
 
-bool Sema::ActOnTypeConstraint(TemplateIdAnnotation *TypeConstr,
+bool Sema::ActOnTypeConstraint(const CXXScopeSpec &SS,
+                               TemplateIdAnnotation *TypeConstr,
                                TemplateTypeParmDecl *ConstrainedParameter,
                                SourceLocation EllipsisLoc) {
   ConceptDecl *CD =
@@ -1080,8 +1081,7 @@ bool Sema::ActOnTypeConstraint(TemplateIdAnnotation *TypeConstr,
         makeTemplateArgumentListInfo(*this, *TypeConstr);
   }
   return AttachTypeConstraint(
-      TypeConstr->SS.isSet() ? TypeConstr->SS.getWithLocInContext(Context) :
-      NestedNameSpecifierLoc(),
+      SS.isSet() ? SS.getWithLocInContext(Context) : NestedNameSpecifierLoc(),
       DeclarationNameInfo(DeclarationName(TypeConstr->Name),
                           TypeConstr->TemplateNameLoc), CD,
       TypeConstr->LAngleLoc.isValid() ? &TemplateArgs : nullptr,
@@ -7872,13 +7872,11 @@ bool Sema::CheckTemplatePartialSpecializationArgs(
 
 DeclResult Sema::ActOnClassTemplateSpecialization(
     Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc,
-    SourceLocation ModulePrivateLoc, TemplateIdAnnotation &TemplateId,
-    const ParsedAttributesView &Attr,
+    SourceLocation ModulePrivateLoc, CXXScopeSpec &SS,
+    TemplateIdAnnotation &TemplateId, const ParsedAttributesView &Attr,
     MultiTemplateParamsArg TemplateParameterLists, SkipBodyInfo *SkipBody) {
   assert(TUK != TUK_Reference && "References are not specializations");
 
-  CXXScopeSpec &SS = TemplateId.SS;
-
   // NOTE: KWLoc is the location of the tag keyword. This will instead
   // store the location of the outermost template keyword in the declaration.
   SourceLocation TemplateKWLoc = TemplateParameterLists.size() > 0
index 68a41c7..6c0df1a 100644 (file)
@@ -16,6 +16,6 @@ template<int n> struct T {
     typename S<k>::T check3; // ok, u is value-dependent
 
     const int &i = k;
-    typename S<i>::T check4; // expected-error {{not an integral constant expression}} expected-error {{qualified name}}
+    typename S<i>::T check4; // expected-error {{not an integral constant expression}}
   }
 };
index a868904..1914f34 100644 (file)
@@ -238,12 +238,11 @@ namespace PR5066 {
 
 namespace PR17255 {
 void foo() {
-  typename A::template B<>; // expected-error {{use of undeclared identifier 'A'}}
-  // expected-error@-1 {{'template' keyword not permitted here}}
+  typename A::template B<> c; // expected-error {{use of undeclared identifier 'A'}}
 #if __cplusplus <= 199711L
+  // expected-error@-2 {{'typename' occurs outside of a template}}
   // expected-error@-3 {{'template' keyword outside of a template}}
 #endif
-  // expected-error@-5 {{expected a qualified name after 'typename'}}
 }
 }
 
index beb64f8..2764648 100644 (file)
@@ -93,7 +93,7 @@ namespace test_undeclared_nontype_parm_arg {
 // template parameter.
 template <typename T> struct Bar { T x; };
 
-template <Bar<Xylophone> *P> // expected-error {{use of undeclared identifier 'Xylophone'}}
+template <Bar<Xylophone> *P> // expected-error {{use of undeclared identifier 'Xylophone'}} expected-note {{declared here}}
 struct Foo { };
 
 typedef int Xylophone;
index ed09a64..76919e2 100644 (file)
@@ -2,8 +2,7 @@
 
 // <rdar://problem/9173693>
 template< bool C > struct assert { };
-// FIXME: We diagnose the same problem multiple times here because we have no
-// way to indicate in the token stream that we already tried to annotate a
-// template-id and we failed.
-template< bool > struct assert_arg_pred_impl { }; // expected-note 4 {{declared here}}
-template< typename Pred > assert<false> assert_not_arg( void (*)(Pred), typename assert_arg_pred<Pred>::type ); // expected-error 6 {{}}
+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@-1 {{did you mean 'assert_arg_pred_impl'}}
+// expected-error@-2 {{template argument for non-type template parameter must be an expression}}