Author: Saar Raz Date: 2020-02-03T15:47:32+02:00 New Revision: eacca4824463d8b96e2e1c9f8bbf886055218a16
URL: https://github.com/llvm/llvm-project/commit/eacca4824463d8b96e2e1c9f8bbf886055218a16 DIFF: https://github.com/llvm/llvm-project/commit/eacca4824463d8b96e2e1c9f8bbf886055218a16.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. 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..8c312c9d2c5a 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,41 @@ 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()) { + // 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; + } + auto *Inst = cast<TemplateTypeParmDecl>( + FindInstantiatedDecl(TTP->getLocation(), TTP, TemplateArgs)); + 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)); _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits