From 69770d3d7a7b988c6f846ca9100b7fdaeac170a1 Mon Sep 17 00:00:00 2001 From: Erik Pilkington Date: Fri, 27 Jul 2018 21:23:48 +0000 Subject: [PATCH] [Sema] Use a TreeTransform to extract deduction guide parameter types Previously, we just canonicalized the type, but this lead to crashes with parameter types that referred to ParmVarDecls of the constructor. There may be more cases that this TreeTransform needs to handle though, such as a constructor parameter type referring to a member in an unevaluated context. Canonicalization doesn't address these cases either though, so we can address them as-needed in follow-up commits. rdar://41330135 Differential revision: https://reviews.llvm.org/D49439 llvm-svn: 338165 --- clang/lib/Sema/SemaTemplate.cpp | 40 ++++++++++++++-------- .../cxx1z-class-template-argument-deduction.cpp | 29 ++++++++++++++++ 2 files changed, 54 insertions(+), 15 deletions(-) diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index dd11632..919bc7b 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -1659,6 +1659,23 @@ DeclResult Sema::CheckClassTemplate( } namespace { +/// Tree transform to "extract" a transformed type from a class template's +/// constructor to a deduction guide. +class ExtractTypeForDeductionGuide + : public TreeTransform { +public: + typedef TreeTransform Base; + ExtractTypeForDeductionGuide(Sema &SemaRef) : Base(SemaRef) {} + + TypeSourceInfo *transform(TypeSourceInfo *TSI) { return TransformType(TSI); } + + QualType TransformTypedefType(TypeLocBuilder &TLB, TypedefTypeLoc TL) { + return TransformType( + TLB, + TL.getTypedefNameDecl()->getTypeSourceInfo()->getTypeLoc()); + } +}; + /// Transform to convert portions of a constructor declaration into the /// corresponding deduction guide, per C++1z [over.match.class.deduct]p1. struct ConvertConstructorToDeductionGuideTransform { @@ -1880,9 +1897,7 @@ private: MultiLevelTemplateArgumentList &Args) { TypeSourceInfo *OldDI = OldParam->getTypeSourceInfo(); TypeSourceInfo *NewDI; - if (!Args.getNumLevels()) - NewDI = OldDI; - else if (auto PackTL = OldDI->getTypeLoc().getAs()) { + if (auto PackTL = OldDI->getTypeLoc().getAs()) { // Expand out the one and only element in each inner pack. Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(SemaRef, 0); NewDI = @@ -1898,23 +1913,17 @@ private: if (!NewDI) return nullptr; - // Canonicalize the type. This (for instance) replaces references to - // typedef members of the current instantiations with the definitions of - // those typedefs, avoiding triggering instantiation of the deduced type - // during deduction. - // FIXME: It would be preferable to retain type sugar and source - // information here (and handle this in substitution instead). - NewDI = SemaRef.Context.getTrivialTypeSourceInfo( - SemaRef.Context.getCanonicalType(NewDI->getType()), - OldParam->getLocation()); + // Extract the type. This (for instance) replaces references to typedef + // members of the current instantiations with the definitions of those + // typedefs, avoiding triggering instantiation of the deduced type during + // deduction. + NewDI = ExtractTypeForDeductionGuide(SemaRef).transform(NewDI); // Resolving a wording defect, we also inherit default arguments from the // constructor. ExprResult NewDefArg; if (OldParam->hasDefaultArg()) { - NewDefArg = Args.getNumLevels() - ? SemaRef.SubstExpr(OldParam->getDefaultArg(), Args) - : OldParam->getDefaultArg(); + NewDefArg = SemaRef.SubstExpr(OldParam->getDefaultArg(), Args); if (NewDefArg.isInvalid()) return nullptr; } @@ -1929,6 +1938,7 @@ private: NewDefArg.get()); NewParam->setScopeInfo(OldParam->getFunctionScopeDepth(), OldParam->getFunctionScopeIndex()); + SemaRef.CurrentInstantiationScope->InstantiatedLocal(OldParam, NewParam); return NewParam; } diff --git a/clang/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp b/clang/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp index f72cb88..cbf7c2e 100644 --- a/clang/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp +++ b/clang/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp @@ -373,6 +373,35 @@ void bar(D& d) { } } +namespace rdar41330135 { +template struct A {}; +template +struct S { + template + S(T a, U t, A); +}; +template struct D { + D(T t, A); +}; +int f() { + S s(0, 0, A()); + D d(0, A()); +} + +namespace test_dupls { +template struct X {}; +template struct A { + A(T t, X); +}; +A a(0, {}); +template struct B { + B(U u, X); +}; +B b(0, {}); +} + +} + #else // expected-no-diagnostics -- 2.7.4