mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-02-11 04:06:20 +00:00
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. llvm-svn: 363972
This commit is contained in:
parent
97dc622ab3
commit
07ed9cfc3e
@ -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<DeclRefExpr>(E)) {
|
||||
const ValueDecl *D = DRE->getDecl();
|
||||
if (isa<VarDecl>(D) || isa<FunctionDecl>(D)) {
|
||||
|
@ -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());
|
||||
|
@ -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<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(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<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(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<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
|
||||
|
@ -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>();
|
||||
}
|
||||
|
@ -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}}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user