From: Richard Smith Date: Thu, 20 Jun 2019 19:49:13 +0000 (+0000) Subject: Fix crash and rejects-valid when a later template parameter or default X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=913a74de66db886e6a276d0644625e46cb549231;p=clang Fix crash and rejects-valid when a later template parameter or default template argument contains a backreference to a dependently-typed earlier parameter. In a case like: template struct X {}; template auto Y = X(); we previously treated both references to `A` in the third parameter as being of type `int` when checking the template-id in `Y`. That`s wrong; the type of `A` in these contexts is the dependent type `U`. When we encounter a non-type template argument that we can't convert to the parameter type because of type-dependence, we now insert a dependent conversion node so that the SubstNonTypeTemplateParmExpr for the template argument will have the parameter's type rather than whatever type the argument had. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@363972 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp index 031aac0dbe..79be51cd9c 100644 --- a/lib/AST/ItaniumMangle.cpp +++ b/lib/AST/ItaniumMangle.cpp @@ -4499,7 +4499,7 @@ void CXXNameMangler::mangleTemplateArg(TemplateArgument A) { // It's possible to end up with a DeclRefExpr here in certain // dependent cases, in which case we should mangle as a // declaration. - const Expr *E = A.getAsExpr()->IgnoreParens(); + const Expr *E = A.getAsExpr()->IgnoreParenImpCasts(); if (const DeclRefExpr *DRE = dyn_cast(E)) { const ValueDecl *D = DRE->getDecl(); if (isa(D) || isa(D)) { diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index d7a05e731e..3941643893 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -491,6 +491,7 @@ ExprResult Sema::ImpCastExprToType(Expr *E, QualType Ty, default: llvm_unreachable("can't implicitly cast lvalue to rvalue with this cast " "kind"); + case CK_Dependent: case CK_LValueToRValue: case CK_ArrayToPointerDecay: case CK_FunctionToPointerDecay: @@ -499,7 +500,8 @@ ExprResult Sema::ImpCastExprToType(Expr *E, QualType Ty, break; } } - assert((VK == VK_RValue || !E->isRValue()) && "can't cast rvalue to lvalue"); + assert((VK == VK_RValue || Kind == CK_Dependent || !E->isRValue()) && + "can't cast rvalue to lvalue"); #endif diagnoseNullableToNonnullConversion(Ty, E->getType(), E->getBeginLoc()); diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 74a891bcb7..7b0a3a3e09 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -4888,10 +4888,22 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param, TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, Converted); - NTTPType = SubstType(NTTPType, - MultiLevelTemplateArgumentList(TemplateArgs), - NTTP->getLocation(), - NTTP->getDeclName()); + + // If the parameter is a pack expansion, expand this slice of the pack. + if (auto *PET = NTTPType->getAs()) { + Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(*this, + ArgumentPackIndex); + NTTPType = SubstType(PET->getPattern(), + MultiLevelTemplateArgumentList(TemplateArgs), + NTTP->getLocation(), + NTTP->getDeclName()); + } else { + NTTPType = SubstType(NTTPType, + MultiLevelTemplateArgumentList(TemplateArgs), + NTTP->getLocation(), + NTTP->getDeclName()); + } + // If that worked, check the non-type template parameter type // for validity. if (!NTTPType.isNull()) @@ -6310,9 +6322,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, // When checking a deduced template argument, deduce from its type even if // the type is dependent, in order to check the types of non-type template // arguments line up properly in partial ordering. - Optional Depth; - if (CTAK != CTAK_Specified) - Depth = Param->getDepth() + 1; + Optional Depth = Param->getDepth() + 1; if (DeduceAutoType( Context.getTrivialTypeSourceInfo(ParamType, Param->getLocation()), Arg, ParamType, Depth) == DAR_Failed) { @@ -6367,9 +6377,24 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, // If either the parameter has a dependent type or the argument is // type-dependent, there's nothing we can check now. if (ParamType->isDependentType() || Arg->isTypeDependent()) { - // FIXME: Produce a cloned, canonical expression? - Converted = TemplateArgument(Arg); - return Arg; + // Force the argument to the type of the parameter to maintain invariants. + auto *PE = dyn_cast(Arg); + if (PE) + Arg = PE->getPattern(); + ExprResult E = ImpCastExprToType( + Arg, ParamType.getNonLValueExprType(Context), CK_Dependent, + ParamType->isLValueReferenceType() ? VK_LValue : + ParamType->isRValueReferenceType() ? VK_XValue : VK_RValue); + if (E.isInvalid()) + return ExprError(); + if (PE) { + // Recreate a pack expansion if we unwrapped one. + E = new (Context) + PackExpansionExpr(E.get()->getType(), E.get(), PE->getEllipsisLoc(), + PE->getNumExpansions()); + } + Converted = TemplateArgument(E.get()); + return E; } // The initialization of the parameter from the argument is diff --git a/test/SemaTemplate/resolve-single-template-id.cpp b/test/SemaTemplate/resolve-single-template-id.cpp index bebca76c4f..9562845a9a 100644 --- a/test/SemaTemplate/resolve-single-template-id.cpp +++ b/test/SemaTemplate/resolve-single-template-id.cpp @@ -88,3 +88,15 @@ struct rdar9108698 { void test_rdar9108698(rdar9108698 x) { x.f; // expected-error{{reference to non-static member function must be called}} } + +namespace GCC_PR67898 { + void f(int); + void f(float); + template struct X { + static_assert(b, ""); + }; + template void test1() { X(); } + template void test2() { X(); } + template void test1(); + template void test2(); +} diff --git a/test/SemaTemplate/temp_arg_nontype.cpp b/test/SemaTemplate/temp_arg_nontype.cpp index 8658fb0060..bdf7663312 100644 --- a/test/SemaTemplate/temp_arg_nontype.cpp +++ b/test/SemaTemplate/temp_arg_nontype.cpp @@ -463,3 +463,22 @@ namespace pointer_to_char_array { T foo = "foo"; void g() { A<&foo>().f(); } } + +namespace dependent_backreference { + struct Incomplete; // expected-note 2{{forward declaration}} + Incomplete f(int); // expected-note 2{{here}} + int f(short); + + template struct X {}; // expected-error 2{{incomplete}} + int arr[sizeof(int)]; + // When checking this template-id, we must not treat 'Value' as having type + // 'int'; its type is the dependent type 'T'. + template void f() { X x; } // expected-note {{substituting}} + void g() { f(); } + void h() { f(); } // expected-note {{instantiation}} + + // The second of these is OK to diagnose eagerly because 'Value' has the + // non-dependent type 'int'. + template void a() { X x; } + template void b() { X x; } // expected-note {{substituting}} +}