Author: rsmith Date: Thu Jun 20 12:49:13 2019 New Revision: 363972 URL: http://llvm.org/viewvc/llvm-project?rev=363972&view=rev Log: 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<typename T, T A, decltype(A) = A> struct X {}; template<typename U> auto Y = X<U, 0>(); 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. Modified: cfe/trunk/lib/AST/ItaniumMangle.cpp cfe/trunk/lib/Sema/Sema.cpp cfe/trunk/lib/Sema/SemaTemplate.cpp cfe/trunk/test/SemaTemplate/resolve-single-template-id.cpp cfe/trunk/test/SemaTemplate/temp_arg_nontype.cpp Modified: cfe/trunk/lib/AST/ItaniumMangle.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ItaniumMangle.cpp?rev=363972&r1=363971&r2=363972&view=diff ============================================================================== --- cfe/trunk/lib/AST/ItaniumMangle.cpp (original) +++ cfe/trunk/lib/AST/ItaniumMangle.cpp Thu Jun 20 12:49:13 2019 @@ -4499,7 +4499,7 @@ void CXXNameMangler::mangleTemplateArg(T // 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<DeclRefExpr>(E)) { const ValueDecl *D = DRE->getDecl(); if (isa<VarDecl>(D) || isa<FunctionDecl>(D)) { Modified: cfe/trunk/lib/Sema/Sema.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.cpp?rev=363972&r1=363971&r2=363972&view=diff ============================================================================== --- cfe/trunk/lib/Sema/Sema.cpp (original) +++ cfe/trunk/lib/Sema/Sema.cpp Thu Jun 20 12:49:13 2019 @@ -491,6 +491,7 @@ ExprResult Sema::ImpCastExprToType(Expr 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 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()); Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=363972&r1=363971&r2=363972&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaTemplate.cpp (original) +++ cfe/trunk/lib/Sema/SemaTemplate.cpp Thu Jun 20 12:49:13 2019 @@ -4888,10 +4888,22 @@ bool Sema::CheckTemplateArgument(NamedDe 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<PackExpansionType>()) { + 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(N // 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<unsigned> Depth; - if (CTAK != CTAK_Specified) - Depth = Param->getDepth() + 1; + Optional<unsigned> Depth = Param->getDepth() + 1; if (DeduceAutoType( Context.getTrivialTypeSourceInfo(ParamType, Param->getLocation()), Arg, ParamType, Depth) == DAR_Failed) { @@ -6367,9 +6377,24 @@ ExprResult Sema::CheckTemplateArgument(N // 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<PackExpansionExpr>(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 Modified: cfe/trunk/test/SemaTemplate/resolve-single-template-id.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/resolve-single-template-id.cpp?rev=363972&r1=363971&r2=363972&view=diff ============================================================================== --- cfe/trunk/test/SemaTemplate/resolve-single-template-id.cpp (original) +++ cfe/trunk/test/SemaTemplate/resolve-single-template-id.cpp Thu Jun 20 12:49:13 2019 @@ -88,3 +88,15 @@ struct rdar9108698 { void test_rdar9108698(rdar9108698 x) { x.f<int>; // expected-error{{reference to non-static member function must be called}} } + +namespace GCC_PR67898 { + void f(int); + void f(float); + template<typename T, T F, T G, bool b = F == G> struct X { + static_assert(b, ""); + }; + template<typename T> void test1() { X<void(T), f, f>(); } + template<typename T> void test2() { X<void(*)(T), f, f>(); } + template void test1<int>(); + template void test2<int>(); +} Modified: cfe/trunk/test/SemaTemplate/temp_arg_nontype.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/temp_arg_nontype.cpp?rev=363972&r1=363971&r2=363972&view=diff ============================================================================== --- cfe/trunk/test/SemaTemplate/temp_arg_nontype.cpp (original) +++ cfe/trunk/test/SemaTemplate/temp_arg_nontype.cpp Thu Jun 20 12:49:13 2019 @@ -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<typename T, T Value, int(*)[sizeof(f(Value))]> 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<typename T> void f() { X<T, 0, &arr> x; } // expected-note {{substituting}} + void g() { f<short>(); } + void h() { f<int>(); } // expected-note {{instantiation}} + + // The second of these is OK to diagnose eagerly because 'Value' has the + // non-dependent type 'int'. + template<short S> void a() { X<short, S, &arr> x; } + template<short S> void b() { X<int, S, &arr> x; } // expected-note {{substituting}} +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits