Author: Saar Raz
Date: 2020-02-06T23:29:07+02:00
New Revision: 38fd69995fc5a6f16e0aa132a46e5ccdbc2eebb3

URL: 
https://github.com/llvm/llvm-project/commit/38fd69995fc5a6f16e0aa132a46e5ccdbc2eebb3
DIFF: 
https://github.com/llvm/llvm-project/commit/38fd69995fc5a6f16e0aa132a46e5ccdbc2eebb3.diff

LOG: [Concepts] Fix incorrect check when instantiating abbreviated template 
type-constraints

We would incorrectly check whether the type-constraint had already been 
initialized, causing us
to ignore the invented template type constraints entirely.

Also, TemplateParameterList would store incorrect information about invented 
type parameters
when it observed them before their type-constraint was initialized, so we 
recreate it after
initializing the function type of an abbreviated template.

Added: 
    

Modified: 
    clang/lib/Sema/SemaTemplateInstantiate.cpp
    clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
    clang/test/SemaTemplate/instantiate-abbreviated-template.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp 
b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index a9357ede700e..568f5404dc0b 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -2290,12 +2290,12 @@ ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl 
*OldParm,
   if (TemplateTypeParmDecl *TTP =
           GetContainedInventedTypeParmVisitor().Visit(OldDI->getType())) {
     if (const TypeConstraint *TC = TTP->getTypeConstraint()) {
-      auto *Inst = cast<TemplateTypeParmDecl>(
+      auto *Inst = cast_or_null<TemplateTypeParmDecl>(
           FindInstantiatedDecl(TTP->getLocation(), TTP, TemplateArgs));
       // We will first get here when instantiating the abbreviated function
       // template's described function, but we might also get here later.
       // Make sure we do not instantiate the TypeConstraint more than once.
-      if (Inst && !Inst->hasTypeConstraint()) {
+      if (Inst && !Inst->getTypeConstraint()) {
         // TODO: Concepts: do not instantiate the constraint (delayed 
constraint
         // substitution)
         const ASTTemplateArgumentListInfo *TemplArgInfo

diff  --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp 
b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 7094462e74c9..37dace3bee7f 100755
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -1837,6 +1837,23 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(
     return nullptr;
   QualType T = adjustFunctionTypeForInstantiation(SemaRef.Context, D, TInfo);
 
+  if (TemplateParams && TemplateParams->size()) {
+    auto *LastParam =
+        dyn_cast<TemplateTypeParmDecl>(TemplateParams->asArray().back());
+    if (LastParam && LastParam->isImplicit() &&
+        LastParam->hasTypeConstraint()) {
+      // In abbreviated templates, the type-constraints of invented template
+      // type parameters are instantiated with the function type, invalidating
+      // the TemplateParameterList which relied on the template type parameter
+      // not having a type constraint. Recreate the TemplateParameterList with
+      // the updated parameter list.
+      TemplateParams = TemplateParameterList::Create(
+          SemaRef.Context, TemplateParams->getTemplateLoc(),
+          TemplateParams->getLAngleLoc(), TemplateParams->asArray(),
+          TemplateParams->getRAngleLoc(), TemplateParams->getRequiresClause());
+    }
+  }
+
   NestedNameSpecifierLoc QualifierLoc = D->getQualifierLoc();
   if (QualifierLoc) {
     QualifierLoc = SemaRef.SubstNestedNameSpecifierLoc(QualifierLoc,
@@ -2177,6 +2194,23 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
     return nullptr;
   QualType T = adjustFunctionTypeForInstantiation(SemaRef.Context, D, TInfo);
 
+  if (TemplateParams && TemplateParams->size()) {
+    auto *LastParam =
+        dyn_cast<TemplateTypeParmDecl>(TemplateParams->asArray().back());
+    if (LastParam && LastParam->isImplicit() &&
+        LastParam->hasTypeConstraint()) {
+      // In abbreviated templates, the type-constraints of invented template
+      // type parameters are instantiated with the function type, invalidating
+      // the TemplateParameterList which relied on the template type parameter
+      // not having a type constraint. Recreate the TemplateParameterList with
+      // the updated parameter list.
+      TemplateParams = TemplateParameterList::Create(
+          SemaRef.Context, TemplateParams->getTemplateLoc(),
+          TemplateParams->getLAngleLoc(), TemplateParams->asArray(),
+          TemplateParams->getRAngleLoc(), TemplateParams->getRequiresClause());
+    }
+  }
+
   NestedNameSpecifierLoc QualifierLoc = D->getQualifierLoc();
   if (QualifierLoc) {
     QualifierLoc = SemaRef.SubstNestedNameSpecifierLoc(QualifierLoc,

diff  --git a/clang/test/SemaTemplate/instantiate-abbreviated-template.cpp 
b/clang/test/SemaTemplate/instantiate-abbreviated-template.cpp
index a73b6ce3610f..99801115626f 100644
--- a/clang/test/SemaTemplate/instantiate-abbreviated-template.cpp
+++ b/clang/test/SemaTemplate/instantiate-abbreviated-template.cpp
@@ -1,29 +1,33 @@
 // RUN: %clang_cc1 -std=c++2a -x c++ %s -verify
-// expected-no-diagnostics
 
 template<typename...>
-concept C = true;
+concept C = false; // expected-note 9{{because}}
 
 template<typename T>
 struct S {
     template<typename U>
     static void foo1(U a, auto b);
     static void foo2(T a, C<T> auto b);
+    // expected-note@-1{{candidate template ignored}} 
expected-note@-1{{because}}
     static void foo3(T a, C<decltype(a)> auto b);
+    // expected-note@-1{{candidate template ignored}} 
expected-note@-1{{because}}
     static void foo4(T a, C<decltype(a)> auto b, const C<decltype(b)> auto 
&&c);
+    // expected-note@-1{{candidate template ignored}} 
expected-note@-1{{because}}
 };
 
 using sf1 = decltype(S<int>::foo1(1, 2));
-using sf2 = decltype(S<int>::foo2(1, 2));
-using sf3 = decltype(S<int>::foo3(1, 2));
-using sf4 = decltype(S<int>::foo4(1, 2, 3));
+using sf2 = decltype(S<int>::foo2(1, 2)); // expected-error{{no matching 
function}}
+using sf3 = decltype(S<int>::foo3(1, 2)); // expected-error{{no matching 
function}}
+using sf4 = decltype(S<int>::foo4(1, 2, 3)); // expected-error{{no matching 
function}}
 
 
 template<typename... T>
 struct G {
     static void foo1(auto a, const C<decltype(a)> auto &&... b);
+    // expected-note@-1{{candidate template ignored}} 
expected-note@-1{{because}} expected-note@-1 3{{and}}
     static void foo2(auto a, const C<decltype(a), T> auto &&... b);
+    // expected-note@-1{{candidate template ignored}} 
expected-note@-1{{because}} expected-note@-1{{and}}
 };
 
-using gf1 = decltype(G<int, char>::foo1('a', 1, 2, 3, 4));
-using gf2 = decltype(G<int, char>::foo2('a', 1, 2));
+using gf1 = decltype(G<int, char>::foo1('a', 1, 2, 3, 4)); // 
expected-error{{no matching function}}
+using gf2 = decltype(G<int, char>::foo2('a', 1, 2)); // expected-error{{no 
matching function}}


        
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to