[llvm-branch-commits] [clang] 1ac1c4b - [Concepts] Instantiate invented template type parameter type-constraint along with function parameters
Saar Raz via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Mon Feb 3 06:53:26 PST 2020
Author: Saar Raz
Date: 2020-02-03T16:53:14+02:00
New Revision: 1ac1c4b4850c1a507caa7da068f44a45ef4ba3c7
URL: https://github.com/llvm/llvm-project/commit/1ac1c4b4850c1a507caa7da068f44a45ef4ba3c7
DIFF: https://github.com/llvm/llvm-project/commit/1ac1c4b4850c1a507caa7da068f44a45ef4ba3c7.diff
LOG: [Concepts] Instantiate invented template type parameter type-constraint along with function parameters
We previously instantiated type-constraints of template type parameters along with the type parameter itself,
this caused problems when the type-constraints created by abbreviated templates refreneced other parameters
in the abbreviated templates.
When encountering a template type parameter with a type constraint, if it is implicit, delay instantiation of
the type-constraint until the function parameter which created the invented template type parameter is
instantiated.
Reland after fixing bug caused by another flow reaching SubstParmVarDecl and instantiating the TypeConstraint
a second time.
(cherry picked from commit 84959ae47f447fca9d56a9c61e8c46e993d0387a)
Added:
clang/test/SemaTemplate/instantiate-abbreviated-template.cpp
Modified:
clang/lib/Sema/SemaTemplateInstantiate.cpp
clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
Removed:
################################################################################
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index dff336f2ff2d..a9357ede700e 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -18,6 +18,7 @@
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
#include "clang/AST/PrettyDeclStackTrace.h"
+#include "clang/AST/TypeVisitor.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/Stack.h"
#include "clang/Sema/DeclSpec.h"
@@ -2145,6 +2146,94 @@ void Sema::SubstExceptionSpec(FunctionDecl *New, const FunctionProtoType *Proto,
UpdateExceptionSpec(New, ESI);
}
+namespace {
+
+ struct GetContainedInventedTypeParmVisitor :
+ public TypeVisitor<GetContainedInventedTypeParmVisitor,
+ TemplateTypeParmDecl *> {
+ using TypeVisitor<GetContainedInventedTypeParmVisitor,
+ TemplateTypeParmDecl *>::Visit;
+
+ TemplateTypeParmDecl *Visit(QualType T) {
+ if (T.isNull())
+ return nullptr;
+ return Visit(T.getTypePtr());
+ }
+ // The deduced type itself.
+ TemplateTypeParmDecl *VisitTemplateTypeParmType(
+ const TemplateTypeParmType *T) {
+ if (!T->getDecl()->isImplicit())
+ return nullptr;
+ return T->getDecl();
+ }
+
+ // Only these types can contain 'auto' types, and subsequently be replaced
+ // by references to invented parameters.
+
+ TemplateTypeParmDecl *VisitElaboratedType(const ElaboratedType *T) {
+ return Visit(T->getNamedType());
+ }
+
+ TemplateTypeParmDecl *VisitPointerType(const PointerType *T) {
+ return Visit(T->getPointeeType());
+ }
+
+ TemplateTypeParmDecl *VisitBlockPointerType(const BlockPointerType *T) {
+ return Visit(T->getPointeeType());
+ }
+
+ TemplateTypeParmDecl *VisitReferenceType(const ReferenceType *T) {
+ return Visit(T->getPointeeTypeAsWritten());
+ }
+
+ TemplateTypeParmDecl *VisitMemberPointerType(const MemberPointerType *T) {
+ return Visit(T->getPointeeType());
+ }
+
+ TemplateTypeParmDecl *VisitArrayType(const ArrayType *T) {
+ return Visit(T->getElementType());
+ }
+
+ TemplateTypeParmDecl *VisitDependentSizedExtVectorType(
+ const DependentSizedExtVectorType *T) {
+ return Visit(T->getElementType());
+ }
+
+ TemplateTypeParmDecl *VisitVectorType(const VectorType *T) {
+ return Visit(T->getElementType());
+ }
+
+ TemplateTypeParmDecl *VisitFunctionProtoType(const FunctionProtoType *T) {
+ return VisitFunctionType(T);
+ }
+
+ TemplateTypeParmDecl *VisitFunctionType(const FunctionType *T) {
+ return Visit(T->getReturnType());
+ }
+
+ TemplateTypeParmDecl *VisitParenType(const ParenType *T) {
+ return Visit(T->getInnerType());
+ }
+
+ TemplateTypeParmDecl *VisitAttributedType(const AttributedType *T) {
+ return Visit(T->getModifiedType());
+ }
+
+ TemplateTypeParmDecl *VisitMacroQualifiedType(const MacroQualifiedType *T) {
+ return Visit(T->getUnderlyingType());
+ }
+
+ TemplateTypeParmDecl *VisitAdjustedType(const AdjustedType *T) {
+ return Visit(T->getOriginalType());
+ }
+
+ TemplateTypeParmDecl *VisitPackExpansionType(const PackExpansionType *T) {
+ return Visit(T->getPattern());
+ }
+ };
+
+} // namespace
+
ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm,
const MultiLevelTemplateArgumentList &TemplateArgs,
int indexAdjustment,
@@ -2192,6 +2281,46 @@ ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm,
return nullptr;
}
+ // In abbreviated templates, TemplateTypeParmDecls with possible
+ // TypeConstraints are created when the parameter list is originally parsed.
+ // The TypeConstraints can therefore reference other functions parameters in
+ // the abbreviated function template, which is why we must instantiate them
+ // here, when the instantiated versions of those referenced parameters are in
+ // scope.
+ if (TemplateTypeParmDecl *TTP =
+ GetContainedInventedTypeParmVisitor().Visit(OldDI->getType())) {
+ if (const TypeConstraint *TC = TTP->getTypeConstraint()) {
+ auto *Inst = cast<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()) {
+ // TODO: Concepts: do not instantiate the constraint (delayed constraint
+ // substitution)
+ const ASTTemplateArgumentListInfo *TemplArgInfo
+ = TC->getTemplateArgsAsWritten();
+ TemplateArgumentListInfo InstArgs;
+
+ if (TemplArgInfo) {
+ InstArgs.setLAngleLoc(TemplArgInfo->LAngleLoc);
+ InstArgs.setRAngleLoc(TemplArgInfo->RAngleLoc);
+ if (Subst(TemplArgInfo->getTemplateArgs(),
+ TemplArgInfo->NumTemplateArgs, InstArgs, TemplateArgs))
+ return nullptr;
+ }
+ if (AttachTypeConstraint(
+ TC->getNestedNameSpecifierLoc(), TC->getConceptNameInfo(),
+ TC->getNamedConcept(), &InstArgs, Inst,
+ TTP->isParameterPack()
+ ? cast<CXXFoldExpr>(TC->getImmediatelyDeclaredConstraint())
+ ->getEllipsisLoc()
+ : SourceLocation()))
+ return nullptr;
+ }
+ }
+ }
+
ParmVarDecl *NewParm = CheckParameter(Context.getTranslationUnitDecl(),
OldParm->getInnerLocStart(),
OldParm->getLocation(),
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 2637b4cb6dca..0e1d5fa77c69 100755
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -2525,28 +2525,34 @@ Decl *TemplateDeclInstantiator::VisitTemplateTypeParmDecl(
Inst->setAccess(AS_public);
Inst->setImplicit(D->isImplicit());
if (auto *TC = D->getTypeConstraint()) {
- // TODO: Concepts: do not instantiate the constraint (delayed constraint
- // substitution)
- const ASTTemplateArgumentListInfo *TemplArgInfo
- = TC->getTemplateArgsAsWritten();
- TemplateArgumentListInfo InstArgs;
-
- if (TemplArgInfo) {
- InstArgs.setLAngleLoc(TemplArgInfo->LAngleLoc);
- InstArgs.setRAngleLoc(TemplArgInfo->RAngleLoc);
- if (SemaRef.Subst(TemplArgInfo->getTemplateArgs(),
- TemplArgInfo->NumTemplateArgs,
- InstArgs, TemplateArgs))
+ if (!D->isImplicit()) {
+ // Invented template parameter type constraints will be instantiated with
+ // the corresponding auto-typed parameter as it might reference other
+ // parameters.
+
+ // TODO: Concepts: do not instantiate the constraint (delayed constraint
+ // substitution)
+ const ASTTemplateArgumentListInfo *TemplArgInfo
+ = TC->getTemplateArgsAsWritten();
+ TemplateArgumentListInfo InstArgs;
+
+ if (TemplArgInfo) {
+ InstArgs.setLAngleLoc(TemplArgInfo->LAngleLoc);
+ InstArgs.setRAngleLoc(TemplArgInfo->RAngleLoc);
+ if (SemaRef.Subst(TemplArgInfo->getTemplateArgs(),
+ TemplArgInfo->NumTemplateArgs,
+ InstArgs, TemplateArgs))
+ return nullptr;
+ }
+ if (SemaRef.AttachTypeConstraint(
+ TC->getNestedNameSpecifierLoc(), TC->getConceptNameInfo(),
+ TC->getNamedConcept(), &InstArgs, Inst,
+ D->isParameterPack()
+ ? cast<CXXFoldExpr>(TC->getImmediatelyDeclaredConstraint())
+ ->getEllipsisLoc()
+ : SourceLocation()))
return nullptr;
}
- if (SemaRef.AttachTypeConstraint(
- TC->getNestedNameSpecifierLoc(), TC->getConceptNameInfo(),
- TC->getNamedConcept(), &InstArgs, Inst,
- D->isParameterPack()
- ? cast<CXXFoldExpr>(TC->getImmediatelyDeclaredConstraint())
- ->getEllipsisLoc()
- : SourceLocation()))
- return nullptr;
}
if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited()) {
TypeSourceInfo *InstantiatedDefaultArg =
diff --git a/clang/test/SemaTemplate/instantiate-abbreviated-template.cpp b/clang/test/SemaTemplate/instantiate-abbreviated-template.cpp
new file mode 100644
index 000000000000..a73b6ce3610f
--- /dev/null
+++ b/clang/test/SemaTemplate/instantiate-abbreviated-template.cpp
@@ -0,0 +1,29 @@
+// RUN: %clang_cc1 -std=c++2a -x c++ %s -verify
+// expected-no-diagnostics
+
+template<typename...>
+concept C = true;
+
+template<typename T>
+struct S {
+ template<typename U>
+ static void foo1(U a, auto b);
+ static void foo2(T a, C<T> auto b);
+ static void foo3(T a, C<decltype(a)> auto b);
+ static void foo4(T a, C<decltype(a)> auto b, const C<decltype(b)> auto &&c);
+};
+
+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));
+
+
+template<typename... T>
+struct G {
+ static void foo1(auto a, const C<decltype(a)> auto &&... b);
+ static void foo2(auto a, const C<decltype(a), T> auto &&... b);
+};
+
+using gf1 = decltype(G<int, char>::foo1('a', 1, 2, 3, 4));
+using gf2 = decltype(G<int, char>::foo2('a', 1, 2));
More information about the llvm-branch-commits
mailing list