erichkeane created this revision. erichkeane added a reviewer: clang-language-wg. Herald added a project: All. erichkeane requested review of this revision.
Two similar bugs were filed, both captured in GH62362. The problem happens when collecting the instantiation args for a constructor with a constraint is inherited by a child class. When the inheriting class itself was NOT a template, the implicit constructor that modeled the inherited constructor is in the declaration context of the inherited type, however it is marked as implicit and as an inheriting constructor. In order to make sure we get the correct instantiation args, this patch recognizes this pattern, and causes us to pick up the instantiation args from the inherited constructor. This also corrects the 'declaration context' to be the ClassTemplateSpecializationDecl of the inherited class, which has the correct instantiation args. however, if the inheriting class is already a template, the correct constructor is actually already picked up, in the correct specialization of the parent class. However, in the case of an explicit specialization, we were skipping the template instantiation args. I found that removing this early-return here actually broke no lit tests, however I still limited the removal of this early return to concept checks. Fixes: #62362 https://reviews.llvm.org/D149264 Files: clang/lib/Sema/SemaTemplateInstantiate.cpp clang/test/SemaTemplate/concepts.cpp Index: clang/test/SemaTemplate/concepts.cpp =================================================================== --- clang/test/SemaTemplate/concepts.cpp +++ clang/test/SemaTemplate/concepts.cpp @@ -816,3 +816,26 @@ static_assert(Parent<int>::TakesBinary<int, 0ULL>::i == 0); } +namespace GH62362 { +template<typename T> +concept C = true; + +template <typename T> struct Test { + Test() + requires(C<T>); +}; + +struct Bar : public Test<int> { + using Test<int>::Test; +}; + +template <> +struct Test<void> : public Test<int> { + using Test<int>::Test; +}; + +void foo() { + Bar(); + Test<void>(); +} +} Index: clang/lib/Sema/SemaTemplateInstantiate.cpp =================================================================== --- clang/lib/Sema/SemaTemplateInstantiate.cpp +++ clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -135,11 +135,13 @@ Response HandleClassTemplateSpec(const ClassTemplateSpecializationDecl *ClassTemplSpec, MultiLevelTemplateArgumentList &Result, - bool SkipForSpecialization) { + bool SkipForSpecialization, + bool ForConstraintInstantiation) { if (!ClassTemplSpec->isClassScopeExplicitSpecialization()) { // We're done when we hit an explicit specialization. if (ClassTemplSpec->getSpecializationKind() == TSK_ExplicitSpecialization && - !isa<ClassTemplatePartialSpecializationDecl>(ClassTemplSpec)) + !isa<ClassTemplatePartialSpecializationDecl>(ClassTemplSpec) && + !ForConstraintInstantiation) return Response::Done(); if (!SkipForSpecialization) @@ -208,6 +210,18 @@ return Response::UseNextDecl(Function); } +Response HandleConstructor(const CXXConstructorDecl *Ctor, + MultiLevelTemplateArgumentList &Result, + const FunctionDecl *Pattern, bool RelativeToPrimary, + bool ForConstraintInstantiation) { + if (Ctor->isImplicit() && Ctor->isInheritingConstructor() && + Ctor->getInheritedConstructor().getConstructor()) + Ctor = Ctor->getInheritedConstructor().getConstructor(); + + return HandleFunction(Ctor, Result, Pattern, RelativeToPrimary, + ForConstraintInstantiation); +} + Response HandleRecordDecl(const CXXRecordDecl *Rec, MultiLevelTemplateArgumentList &Result, ASTContext &Context, @@ -308,8 +322,11 @@ R = HandleVarTemplateSpec(VarTemplSpec, Result, SkipForSpecialization); } else if (const auto *ClassTemplSpec = dyn_cast<ClassTemplateSpecializationDecl>(CurDecl)) { - R = HandleClassTemplateSpec(ClassTemplSpec, Result, - SkipForSpecialization); + R = HandleClassTemplateSpec(ClassTemplSpec, Result, SkipForSpecialization, + ForConstraintInstantiation); + } else if (const auto *Ctor = dyn_cast<CXXConstructorDecl>(CurDecl)) { + R = HandleConstructor(Ctor, Result, Pattern, RelativeToPrimary, + ForConstraintInstantiation); } else if (const auto *Function = dyn_cast<FunctionDecl>(CurDecl)) { R = HandleFunction(Function, Result, Pattern, RelativeToPrimary, ForConstraintInstantiation);
Index: clang/test/SemaTemplate/concepts.cpp =================================================================== --- clang/test/SemaTemplate/concepts.cpp +++ clang/test/SemaTemplate/concepts.cpp @@ -816,3 +816,26 @@ static_assert(Parent<int>::TakesBinary<int, 0ULL>::i == 0); } +namespace GH62362 { +template<typename T> +concept C = true; + +template <typename T> struct Test { + Test() + requires(C<T>); +}; + +struct Bar : public Test<int> { + using Test<int>::Test; +}; + +template <> +struct Test<void> : public Test<int> { + using Test<int>::Test; +}; + +void foo() { + Bar(); + Test<void>(); +} +} Index: clang/lib/Sema/SemaTemplateInstantiate.cpp =================================================================== --- clang/lib/Sema/SemaTemplateInstantiate.cpp +++ clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -135,11 +135,13 @@ Response HandleClassTemplateSpec(const ClassTemplateSpecializationDecl *ClassTemplSpec, MultiLevelTemplateArgumentList &Result, - bool SkipForSpecialization) { + bool SkipForSpecialization, + bool ForConstraintInstantiation) { if (!ClassTemplSpec->isClassScopeExplicitSpecialization()) { // We're done when we hit an explicit specialization. if (ClassTemplSpec->getSpecializationKind() == TSK_ExplicitSpecialization && - !isa<ClassTemplatePartialSpecializationDecl>(ClassTemplSpec)) + !isa<ClassTemplatePartialSpecializationDecl>(ClassTemplSpec) && + !ForConstraintInstantiation) return Response::Done(); if (!SkipForSpecialization) @@ -208,6 +210,18 @@ return Response::UseNextDecl(Function); } +Response HandleConstructor(const CXXConstructorDecl *Ctor, + MultiLevelTemplateArgumentList &Result, + const FunctionDecl *Pattern, bool RelativeToPrimary, + bool ForConstraintInstantiation) { + if (Ctor->isImplicit() && Ctor->isInheritingConstructor() && + Ctor->getInheritedConstructor().getConstructor()) + Ctor = Ctor->getInheritedConstructor().getConstructor(); + + return HandleFunction(Ctor, Result, Pattern, RelativeToPrimary, + ForConstraintInstantiation); +} + Response HandleRecordDecl(const CXXRecordDecl *Rec, MultiLevelTemplateArgumentList &Result, ASTContext &Context, @@ -308,8 +322,11 @@ R = HandleVarTemplateSpec(VarTemplSpec, Result, SkipForSpecialization); } else if (const auto *ClassTemplSpec = dyn_cast<ClassTemplateSpecializationDecl>(CurDecl)) { - R = HandleClassTemplateSpec(ClassTemplSpec, Result, - SkipForSpecialization); + R = HandleClassTemplateSpec(ClassTemplSpec, Result, SkipForSpecialization, + ForConstraintInstantiation); + } else if (const auto *Ctor = dyn_cast<CXXConstructorDecl>(CurDecl)) { + R = HandleConstructor(Ctor, Result, Pattern, RelativeToPrimary, + ForConstraintInstantiation); } else if (const auto *Function = dyn_cast<FunctionDecl>(CurDecl)) { R = HandleFunction(Function, Result, Pattern, RelativeToPrimary, ForConstraintInstantiation);
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits