forked from OSchip/llvm-project
Consider reference, pointer, and pointer-to-member TemplateArguments to be different if they have different types.
For the Itanium ABI, this implements the mangling rule suggested in https://github.com/itanium-cxx-abi/cxx-abi/issues/47, namely mangling such template arguments as being cast to the parameter type in the case where the template name is overloadable. This can cause a mangling change for rare cases, where * the template argument declaration is converted from its declared type to the type of the template parameter, and * the template parameter either has a deduced type or is a parameter of a function template. However, such changes are necessary to avoid mangling collisions. The ABI changes can be reversed with -fclang-abi-compat=11 or earlier. Re-commit with a fix for the regression introduced last time: don't expect parameters and arguments to line up inside an <unresolved-name> mangling. Differential Revision: https://reviews.llvm.org/D91488
This commit is contained in:
parent
abbd57e558
commit
05cdf4acf4
|
@ -155,8 +155,10 @@ public:
|
|||
|
||||
/// Attempt to be ABI-compatible with code generated by Clang 11.0.x
|
||||
/// (git 2e10b7a39b93). This causes clang to pass unions with a 256-bit
|
||||
/// vector member on the stack instead of using registers, and to not
|
||||
/// properly mangle substitutions for template names in some cases.
|
||||
/// vector member on the stack instead of using registers, to not properly
|
||||
/// mangle substitutions for template names in some cases, and to mangle
|
||||
/// declaration template arguments without a cast to the parameter type
|
||||
/// even when that can lead to mangling collisions.
|
||||
Ver11,
|
||||
|
||||
/// Conform to the underlying platform's C and C++ ABIs as closely
|
||||
|
|
|
@ -551,13 +551,15 @@ private:
|
|||
void mangleCXXCtorType(CXXCtorType T, const CXXRecordDecl *InheritedFrom);
|
||||
void mangleCXXDtorType(CXXDtorType T);
|
||||
|
||||
void mangleTemplateArgs(const TemplateArgumentLoc *TemplateArgs,
|
||||
void mangleTemplateArgs(TemplateName TN,
|
||||
const TemplateArgumentLoc *TemplateArgs,
|
||||
unsigned NumTemplateArgs);
|
||||
void mangleTemplateArgs(const TemplateArgument *TemplateArgs,
|
||||
void mangleTemplateArgs(TemplateName TN, const TemplateArgument *TemplateArgs,
|
||||
unsigned NumTemplateArgs);
|
||||
void mangleTemplateArgs(const TemplateArgumentList &AL);
|
||||
void mangleTemplateArg(TemplateArgument A);
|
||||
void mangleValueInTemplateArg(QualType T, const APValue &V);
|
||||
void mangleTemplateArgs(TemplateName TN, const TemplateArgumentList &AL);
|
||||
void mangleTemplateArg(TemplateArgument A, bool NeedExactType);
|
||||
void mangleValueInTemplateArg(QualType T, const APValue &V, bool TopLevel,
|
||||
bool NeedExactType = false);
|
||||
|
||||
void mangleTemplateParameter(unsigned Depth, unsigned Index);
|
||||
|
||||
|
@ -823,6 +825,11 @@ isTemplate(GlobalDecl GD, const TemplateArgumentList *&TemplateArgs) {
|
|||
return GlobalDecl();
|
||||
}
|
||||
|
||||
static TemplateName asTemplateName(GlobalDecl GD) {
|
||||
const TemplateDecl *TD = dyn_cast_or_null<TemplateDecl>(GD.getDecl());
|
||||
return TemplateName(const_cast<TemplateDecl*>(TD));
|
||||
}
|
||||
|
||||
void CXXNameMangler::mangleName(GlobalDecl GD) {
|
||||
const NamedDecl *ND = cast<NamedDecl>(GD.getDecl());
|
||||
if (const VarDecl *VD = dyn_cast<VarDecl>(ND)) {
|
||||
|
@ -899,7 +906,7 @@ void CXXNameMangler::mangleNameWithAbiTags(GlobalDecl GD,
|
|||
const TemplateArgumentList *TemplateArgs = nullptr;
|
||||
if (GlobalDecl TD = isTemplate(GD, TemplateArgs)) {
|
||||
mangleUnscopedTemplateName(TD, AdditionalAbiTags);
|
||||
mangleTemplateArgs(*TemplateArgs);
|
||||
mangleTemplateArgs(asTemplateName(TD), *TemplateArgs);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -952,7 +959,7 @@ void CXXNameMangler::mangleTemplateName(const TemplateDecl *TD,
|
|||
|
||||
if (DC->isTranslationUnit() || isStdNamespace(DC)) {
|
||||
mangleUnscopedTemplateName(TD, nullptr);
|
||||
mangleTemplateArgs(TemplateArgs, NumTemplateArgs);
|
||||
mangleTemplateArgs(asTemplateName(TD), TemplateArgs, NumTemplateArgs);
|
||||
} else {
|
||||
mangleNestedName(TD, TemplateArgs, NumTemplateArgs);
|
||||
}
|
||||
|
@ -1102,7 +1109,8 @@ void CXXNameMangler::manglePrefix(QualType type) {
|
|||
// FIXME: GCC does not appear to mangle the template arguments when
|
||||
// the template in question is a dependent template name. Should we
|
||||
// emulate that badness?
|
||||
mangleTemplateArgs(TST->getArgs(), TST->getNumArgs());
|
||||
mangleTemplateArgs(TST->getTemplateName(), TST->getArgs(),
|
||||
TST->getNumArgs());
|
||||
addSubstitution(QualType(TST, 0));
|
||||
}
|
||||
} else if (const auto *DTST =
|
||||
|
@ -1115,7 +1123,7 @@ void CXXNameMangler::manglePrefix(QualType type) {
|
|||
// FIXME: GCC does not appear to mangle the template arguments when
|
||||
// the template in question is a dependent template name. Should we
|
||||
// emulate that badness?
|
||||
mangleTemplateArgs(DTST->getArgs(), DTST->getNumArgs());
|
||||
mangleTemplateArgs(Template, DTST->getArgs(), DTST->getNumArgs());
|
||||
addSubstitution(QualType(DTST, 0));
|
||||
}
|
||||
} else {
|
||||
|
@ -1258,7 +1266,7 @@ void CXXNameMangler::mangleUnresolvedName(
|
|||
// The <simple-id> and on <operator-name> productions end in an optional
|
||||
// <template-args>.
|
||||
if (TemplateArgs)
|
||||
mangleTemplateArgs(TemplateArgs, NumTemplateArgs);
|
||||
mangleTemplateArgs(TemplateName(), TemplateArgs, NumTemplateArgs);
|
||||
}
|
||||
|
||||
void CXXNameMangler::mangleUnqualifiedName(GlobalDecl GD,
|
||||
|
@ -1303,10 +1311,9 @@ void CXXNameMangler::mangleUnqualifiedName(GlobalDecl GD,
|
|||
|
||||
if (auto *TPO = dyn_cast<TemplateParamObjectDecl>(ND)) {
|
||||
// Proposed in https://github.com/itanium-cxx-abi/cxx-abi/issues/63.
|
||||
Out << "TAX";
|
||||
Out << "TA";
|
||||
mangleValueInTemplateArg(TPO->getType().getUnqualifiedType(),
|
||||
TPO->getValue());
|
||||
Out << "E";
|
||||
TPO->getValue(), /*TopLevel=*/true);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1458,10 +1465,13 @@ void CXXNameMangler::mangleUnqualifiedName(GlobalDecl GD,
|
|||
|
||||
case DeclarationName::CXXConstructorName: {
|
||||
const CXXRecordDecl *InheritedFrom = nullptr;
|
||||
TemplateName InheritedTemplateName;
|
||||
const TemplateArgumentList *InheritedTemplateArgs = nullptr;
|
||||
if (auto Inherited =
|
||||
cast<CXXConstructorDecl>(ND)->getInheritedConstructor()) {
|
||||
InheritedFrom = Inherited.getConstructor()->getParent();
|
||||
InheritedTemplateName =
|
||||
TemplateName(Inherited.getConstructor()->getPrimaryTemplate());
|
||||
InheritedTemplateArgs =
|
||||
Inherited.getConstructor()->getTemplateSpecializationArgs();
|
||||
}
|
||||
|
@ -1478,7 +1488,7 @@ void CXXNameMangler::mangleUnqualifiedName(GlobalDecl GD,
|
|||
// FIXME: The template arguments are part of the enclosing prefix or
|
||||
// nested-name, but it's more convenient to mangle them here.
|
||||
if (InheritedTemplateArgs)
|
||||
mangleTemplateArgs(*InheritedTemplateArgs);
|
||||
mangleTemplateArgs(InheritedTemplateName, *InheritedTemplateArgs);
|
||||
|
||||
writeAbiTags(ND, AdditionalAbiTags);
|
||||
break;
|
||||
|
@ -1567,7 +1577,7 @@ void CXXNameMangler::mangleNestedName(GlobalDecl GD,
|
|||
const TemplateArgumentList *TemplateArgs = nullptr;
|
||||
if (GlobalDecl TD = isTemplate(GD, TemplateArgs)) {
|
||||
mangleTemplatePrefix(TD, NoFunction);
|
||||
mangleTemplateArgs(*TemplateArgs);
|
||||
mangleTemplateArgs(asTemplateName(TD), *TemplateArgs);
|
||||
}
|
||||
else {
|
||||
manglePrefix(DC, NoFunction);
|
||||
|
@ -1584,7 +1594,7 @@ void CXXNameMangler::mangleNestedName(const TemplateDecl *TD,
|
|||
Out << 'N';
|
||||
|
||||
mangleTemplatePrefix(TD);
|
||||
mangleTemplateArgs(TemplateArgs, NumTemplateArgs);
|
||||
mangleTemplateArgs(asTemplateName(TD), TemplateArgs, NumTemplateArgs);
|
||||
|
||||
Out << 'E';
|
||||
}
|
||||
|
@ -1811,8 +1821,8 @@ void CXXNameMangler::mangleLambda(const CXXRecordDecl *Lambda) {
|
|||
= cast<NamedDecl>(Context)->getIdentifier()) {
|
||||
mangleSourceName(Name);
|
||||
const TemplateArgumentList *TemplateArgs = nullptr;
|
||||
if (isTemplate(cast<NamedDecl>(Context), TemplateArgs))
|
||||
mangleTemplateArgs(*TemplateArgs);
|
||||
if (GlobalDecl TD = isTemplate(cast<NamedDecl>(Context), TemplateArgs))
|
||||
mangleTemplateArgs(asTemplateName(TD), *TemplateArgs);
|
||||
Out << 'M';
|
||||
}
|
||||
}
|
||||
|
@ -1903,7 +1913,7 @@ void CXXNameMangler::manglePrefix(const DeclContext *DC, bool NoFunction) {
|
|||
const TemplateArgumentList *TemplateArgs = nullptr;
|
||||
if (GlobalDecl TD = isTemplate(ND, TemplateArgs)) {
|
||||
mangleTemplatePrefix(TD);
|
||||
mangleTemplateArgs(*TemplateArgs);
|
||||
mangleTemplateArgs(asTemplateName(TD), *TemplateArgs);
|
||||
} else {
|
||||
manglePrefix(getEffectiveDeclContext(ND), NoFunction);
|
||||
mangleUnqualifiedName(ND, nullptr);
|
||||
|
@ -2162,7 +2172,12 @@ bool CXXNameMangler::mangleUnresolvedTypeOrSimpleId(QualType Ty,
|
|||
}
|
||||
}
|
||||
|
||||
mangleTemplateArgs(TST->getArgs(), TST->getNumArgs());
|
||||
// Note: we don't pass in the template name here. We are mangling the
|
||||
// original source-level template arguments, so we shouldn't consider
|
||||
// conversions to the corresponding template parameter.
|
||||
// FIXME: Other compilers mangle partially-resolved template arguments in
|
||||
// unresolved-qualifier-levels.
|
||||
mangleTemplateArgs(TemplateName(), TST->getArgs(), TST->getNumArgs());
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -2178,8 +2193,10 @@ bool CXXNameMangler::mangleUnresolvedTypeOrSimpleId(QualType Ty,
|
|||
case Type::DependentTemplateSpecialization: {
|
||||
const DependentTemplateSpecializationType *DTST =
|
||||
cast<DependentTemplateSpecializationType>(Ty);
|
||||
TemplateName Template = getASTContext().getDependentTemplateName(
|
||||
DTST->getQualifier(), DTST->getIdentifier());
|
||||
mangleSourceName(DTST->getIdentifier());
|
||||
mangleTemplateArgs(DTST->getArgs(), DTST->getNumArgs());
|
||||
mangleTemplateArgs(Template, DTST->getArgs(), DTST->getNumArgs());
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -3507,8 +3524,8 @@ void CXXNameMangler::mangleType(const DependentSizedMatrixType *T) {
|
|||
Out << "u" << VendorQualifier.size() << VendorQualifier;
|
||||
|
||||
Out << "I";
|
||||
mangleTemplateArg(T->getRowExpr());
|
||||
mangleTemplateArg(T->getColumnExpr());
|
||||
mangleTemplateArg(T->getRowExpr(), false);
|
||||
mangleTemplateArg(T->getColumnExpr(), false);
|
||||
mangleType(T->getElementType());
|
||||
Out << "E";
|
||||
}
|
||||
|
@ -3581,7 +3598,7 @@ void CXXNameMangler::mangleType(const TemplateSpecializationType *T) {
|
|||
// FIXME: GCC does not appear to mangle the template arguments when
|
||||
// the template in question is a dependent template name. Should we
|
||||
// emulate that badness?
|
||||
mangleTemplateArgs(T->getArgs(), T->getNumArgs());
|
||||
mangleTemplateArgs(T->getTemplateName(), T->getArgs(), T->getNumArgs());
|
||||
addSubstitution(QualType(T, 0));
|
||||
}
|
||||
}
|
||||
|
@ -3633,7 +3650,7 @@ void CXXNameMangler::mangleType(const DependentTemplateSpecializationType *T) {
|
|||
// FIXME: GCC does not appear to mangle the template arguments when
|
||||
// the template in question is a dependent template name. Should we
|
||||
// emulate that badness?
|
||||
mangleTemplateArgs(T->getArgs(), T->getNumArgs());
|
||||
mangleTemplateArgs(Prefix, T->getArgs(), T->getNumArgs());
|
||||
Out << 'E';
|
||||
}
|
||||
|
||||
|
@ -3733,7 +3750,7 @@ void CXXNameMangler::mangleType(const ExtIntType *T) {
|
|||
llvm::APSInt BW(32, true);
|
||||
BW = T->getNumBits();
|
||||
TemplateArgument TA(Context.getASTContext(), BW, getASTContext().IntTy);
|
||||
mangleTemplateArgs(&TA, 1);
|
||||
mangleTemplateArgs(TemplateName(), &TA, 1);
|
||||
if (T->isUnsigned())
|
||||
Out << "j";
|
||||
else
|
||||
|
@ -3743,7 +3760,7 @@ void CXXNameMangler::mangleType(const ExtIntType *T) {
|
|||
void CXXNameMangler::mangleType(const DependentExtIntType *T) {
|
||||
Out << "U7_ExtInt";
|
||||
TemplateArgument TA(T->getNumBitsExpr());
|
||||
mangleTemplateArgs(&TA, 1);
|
||||
mangleTemplateArgs(TemplateName(), &TA, 1);
|
||||
if (T->isUnsigned())
|
||||
Out << "j";
|
||||
else
|
||||
|
@ -4632,7 +4649,7 @@ recurse:
|
|||
if (SPE->isPartiallySubstituted()) {
|
||||
Out << "sP";
|
||||
for (const auto &A : SPE->getPartialArguments())
|
||||
mangleTemplateArg(A);
|
||||
mangleTemplateArg(A, false);
|
||||
Out << "E";
|
||||
break;
|
||||
}
|
||||
|
@ -4820,33 +4837,95 @@ void CXXNameMangler::mangleCXXDtorType(CXXDtorType T) {
|
|||
}
|
||||
}
|
||||
|
||||
void CXXNameMangler::mangleTemplateArgs(const TemplateArgumentLoc *TemplateArgs,
|
||||
namespace {
|
||||
// Helper to provide ancillary information on a template used to mangle its
|
||||
// arguments.
|
||||
struct TemplateArgManglingInfo {
|
||||
TemplateDecl *ResolvedTemplate = nullptr;
|
||||
bool SeenPackExpansionIntoNonPack = false;
|
||||
|
||||
TemplateArgManglingInfo(TemplateName TN) {
|
||||
if (TemplateDecl *TD = TN.getAsTemplateDecl())
|
||||
ResolvedTemplate = TD;
|
||||
}
|
||||
|
||||
/// Do we need to mangle template arguments with exactly correct types?
|
||||
///
|
||||
/// This should be called exactly once for each parameter / argument pair, in
|
||||
/// order.
|
||||
bool needExactType(unsigned ParamIdx, const TemplateArgument &Arg) {
|
||||
// We need correct types when the template-name is unresolved or when it
|
||||
// names a template that is able to be overloaded.
|
||||
if (!ResolvedTemplate || SeenPackExpansionIntoNonPack)
|
||||
return true;
|
||||
|
||||
// If we encounter a pack argument that is expanded into a non-pack
|
||||
// parameter, we can no longer track parameter / argument correspondence,
|
||||
// and need to use exact types from this point onwards.
|
||||
assert(ParamIdx < ResolvedTemplate->getTemplateParameters()->size() &&
|
||||
"no parameter for argument");
|
||||
const NamedDecl *Param =
|
||||
ResolvedTemplate->getTemplateParameters()->getParam(ParamIdx);
|
||||
if (!Param->isParameterPack() && Arg.isPackExpansion()) {
|
||||
SeenPackExpansionIntoNonPack = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
assert(Param->isParameterPack() ==
|
||||
(Arg.getKind() == TemplateArgument::Pack) &&
|
||||
"should have formed pack argument for pack parameter");
|
||||
|
||||
// We need exact types for function template arguments because they might be
|
||||
// overloaded on template parameter type. As a special case, a member
|
||||
// function template of a generic lambda is not overloadable.
|
||||
if (auto *FTD = dyn_cast<FunctionTemplateDecl>(ResolvedTemplate)) {
|
||||
auto *RD = dyn_cast<CXXRecordDecl>(FTD->getDeclContext());
|
||||
if (!RD || !RD->isGenericLambda())
|
||||
return true;
|
||||
}
|
||||
|
||||
// Otherwise, we only need a correct type if the parameter has a deduced
|
||||
// type.
|
||||
auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Param);
|
||||
return NTTP && NTTP->getType()->getContainedDeducedType();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
void CXXNameMangler::mangleTemplateArgs(TemplateName TN,
|
||||
const TemplateArgumentLoc *TemplateArgs,
|
||||
unsigned NumTemplateArgs) {
|
||||
// <template-args> ::= I <template-arg>+ E
|
||||
Out << 'I';
|
||||
TemplateArgManglingInfo Info(TN);
|
||||
for (unsigned i = 0; i != NumTemplateArgs; ++i)
|
||||
mangleTemplateArg(TemplateArgs[i].getArgument());
|
||||
mangleTemplateArg(TemplateArgs[i].getArgument(),
|
||||
Info.needExactType(i, TemplateArgs[i].getArgument()));
|
||||
Out << 'E';
|
||||
}
|
||||
|
||||
void CXXNameMangler::mangleTemplateArgs(const TemplateArgumentList &AL) {
|
||||
void CXXNameMangler::mangleTemplateArgs(TemplateName TN,
|
||||
const TemplateArgumentList &AL) {
|
||||
// <template-args> ::= I <template-arg>+ E
|
||||
Out << 'I';
|
||||
TemplateArgManglingInfo Info(TN);
|
||||
for (unsigned i = 0, e = AL.size(); i != e; ++i)
|
||||
mangleTemplateArg(AL[i]);
|
||||
mangleTemplateArg(AL[i], Info.needExactType(i, AL[i]));
|
||||
Out << 'E';
|
||||
}
|
||||
|
||||
void CXXNameMangler::mangleTemplateArgs(const TemplateArgument *TemplateArgs,
|
||||
void CXXNameMangler::mangleTemplateArgs(TemplateName TN,
|
||||
const TemplateArgument *TemplateArgs,
|
||||
unsigned NumTemplateArgs) {
|
||||
// <template-args> ::= I <template-arg>+ E
|
||||
Out << 'I';
|
||||
TemplateArgManglingInfo Info(TN);
|
||||
for (unsigned i = 0; i != NumTemplateArgs; ++i)
|
||||
mangleTemplateArg(TemplateArgs[i]);
|
||||
mangleTemplateArg(TemplateArgs[i], Info.needExactType(i, TemplateArgs[i]));
|
||||
Out << 'E';
|
||||
}
|
||||
|
||||
void CXXNameMangler::mangleTemplateArg(TemplateArgument A) {
|
||||
void CXXNameMangler::mangleTemplateArg(TemplateArgument A, bool NeedExactType) {
|
||||
// <template-arg> ::= <type> # type or template
|
||||
// ::= X <expression> E # expression
|
||||
// ::= <expr-primary> # simple expressions
|
||||
|
@ -4900,28 +4979,34 @@ void CXXNameMangler::mangleTemplateArg(TemplateArgument A) {
|
|||
// Template parameter objects are modeled by reproducing a source form
|
||||
// produced as if by aggregate initialization.
|
||||
if (A.getParamTypeForDecl()->isRecordType()) {
|
||||
Out << 'X';
|
||||
auto *TPO = cast<TemplateParamObjectDecl>(D);
|
||||
mangleValueInTemplateArg(TPO->getType().getUnqualifiedType(),
|
||||
TPO->getValue());
|
||||
Out << 'E';
|
||||
TPO->getValue(), /*TopLevel=*/true,
|
||||
NeedExactType);
|
||||
break;
|
||||
}
|
||||
|
||||
// Clang produces AST's where pointer-to-member-function expressions
|
||||
// and pointer-to-function expressions are represented as a declaration not
|
||||
// an expression. We compensate for it here to produce the correct mangling.
|
||||
bool compensateMangling = !A.getParamTypeForDecl()->isReferenceType();
|
||||
if (compensateMangling) {
|
||||
Out << 'X';
|
||||
mangleOperatorName(OO_Amp, 1);
|
||||
}
|
||||
|
||||
mangleDeclRefExpr(D);
|
||||
|
||||
if (compensateMangling)
|
||||
Out << 'E';
|
||||
|
||||
ASTContext &Ctx = Context.getASTContext();
|
||||
APValue Value;
|
||||
if (D->isCXXInstanceMember())
|
||||
// Simple pointer-to-member with no conversion.
|
||||
Value = APValue(D, /*IsDerivedMember=*/false, /*Path=*/{});
|
||||
else if (D->getType()->isArrayType() &&
|
||||
Ctx.hasSimilarType(Ctx.getDecayedType(D->getType()),
|
||||
A.getParamTypeForDecl()) &&
|
||||
Ctx.getLangOpts().getClangABICompat() >
|
||||
LangOptions::ClangABI::Ver11)
|
||||
// Build a value corresponding to this implicit array-to-pointer decay.
|
||||
Value = APValue(APValue::LValueBase(D), CharUnits::Zero(),
|
||||
{APValue::LValuePathEntry::ArrayIndex(0)},
|
||||
/*OnePastTheEnd=*/false);
|
||||
else
|
||||
// Regular pointer or reference to a declaration.
|
||||
Value = APValue(APValue::LValueBase(D), CharUnits::Zero(),
|
||||
ArrayRef<APValue::LValuePathEntry>(),
|
||||
/*OnePastTheEnd=*/false);
|
||||
mangleValueInTemplateArg(A.getParamTypeForDecl(), Value, /*TopLevel=*/true,
|
||||
NeedExactType);
|
||||
break;
|
||||
}
|
||||
case TemplateArgument::NullPtr: {
|
||||
|
@ -4932,7 +5017,7 @@ void CXXNameMangler::mangleTemplateArg(TemplateArgument A) {
|
|||
// <template-arg> ::= J <template-arg>* E
|
||||
Out << 'J';
|
||||
for (const auto &P : A.pack_elements())
|
||||
mangleTemplateArg(P);
|
||||
mangleTemplateArg(P, NeedExactType);
|
||||
Out << 'E';
|
||||
}
|
||||
}
|
||||
|
@ -5028,11 +5113,36 @@ static bool isZeroInitialized(QualType T, const APValue &V) {
|
|||
llvm_unreachable("Unhandled APValue::ValueKind enum");
|
||||
}
|
||||
|
||||
void CXXNameMangler::mangleValueInTemplateArg(QualType T, const APValue &V) {
|
||||
static QualType getLValueType(ASTContext &Ctx, const APValue &LV) {
|
||||
QualType T = LV.getLValueBase().getType();
|
||||
for (APValue::LValuePathEntry E : LV.getLValuePath()) {
|
||||
if (const ArrayType *AT = Ctx.getAsArrayType(T))
|
||||
T = AT->getElementType();
|
||||
else if (const FieldDecl *FD =
|
||||
dyn_cast<FieldDecl>(E.getAsBaseOrMember().getPointer()))
|
||||
T = FD->getType();
|
||||
else
|
||||
T = Ctx.getRecordType(
|
||||
cast<CXXRecordDecl>(E.getAsBaseOrMember().getPointer()));
|
||||
}
|
||||
return T;
|
||||
}
|
||||
|
||||
void CXXNameMangler::mangleValueInTemplateArg(QualType T, const APValue &V,
|
||||
bool TopLevel,
|
||||
bool NeedExactType) {
|
||||
// Ignore all top-level cv-qualifiers, to match GCC.
|
||||
Qualifiers Quals;
|
||||
T = getASTContext().getUnqualifiedArrayType(T, Quals);
|
||||
|
||||
// A top-level expression that's not a primary expression is wrapped in X...E.
|
||||
bool IsPrimaryExpr = true;
|
||||
auto NotPrimaryExpr = [&] {
|
||||
if (TopLevel && IsPrimaryExpr)
|
||||
Out << 'X';
|
||||
IsPrimaryExpr = false;
|
||||
};
|
||||
|
||||
// Proposed in https://github.com/itanium-cxx-abi/cxx-abi/issues/63.
|
||||
switch (V.getKind()) {
|
||||
case APValue::None:
|
||||
|
@ -5040,7 +5150,7 @@ void CXXNameMangler::mangleValueInTemplateArg(QualType T, const APValue &V) {
|
|||
Out << 'L';
|
||||
mangleType(T);
|
||||
Out << 'E';
|
||||
return;
|
||||
break;
|
||||
|
||||
case APValue::AddrLabelDiff:
|
||||
llvm_unreachable("unexpected value kind in template argument");
|
||||
|
@ -5068,18 +5178,20 @@ void CXXNameMangler::mangleValueInTemplateArg(QualType T, const APValue &V) {
|
|||
}
|
||||
|
||||
// <expression> ::= tl <type> <braced-expression>* E
|
||||
NotPrimaryExpr();
|
||||
Out << "tl";
|
||||
mangleType(T);
|
||||
for (unsigned I = 0, N = Bases.size(); I != N; ++I)
|
||||
mangleValueInTemplateArg(Bases[I].getType(), V.getStructBase(I));
|
||||
mangleValueInTemplateArg(Bases[I].getType(), V.getStructBase(I), false);
|
||||
for (unsigned I = 0, N = Fields.size(); I != N; ++I) {
|
||||
if (Fields[I]->isUnnamedBitfield())
|
||||
continue;
|
||||
mangleValueInTemplateArg(Fields[I]->getType(),
|
||||
V.getStructField(Fields[I]->getFieldIndex()));
|
||||
V.getStructField(Fields[I]->getFieldIndex()),
|
||||
false);
|
||||
}
|
||||
Out << 'E';
|
||||
return;
|
||||
break;
|
||||
}
|
||||
|
||||
case APValue::Union: {
|
||||
|
@ -5090,24 +5202,26 @@ void CXXNameMangler::mangleValueInTemplateArg(QualType T, const APValue &V) {
|
|||
Out << 'L';
|
||||
mangleType(T);
|
||||
Out << 'E';
|
||||
return;
|
||||
break;
|
||||
}
|
||||
|
||||
// <braced-expression> ::= di <field source-name> <braced-expression>
|
||||
NotPrimaryExpr();
|
||||
Out << "tl";
|
||||
mangleType(T);
|
||||
if (!isZeroInitialized(T, V)) {
|
||||
Out << "di";
|
||||
mangleSourceName(FD->getIdentifier());
|
||||
mangleValueInTemplateArg(FD->getType(), V.getUnionValue());
|
||||
mangleValueInTemplateArg(FD->getType(), V.getUnionValue(), false);
|
||||
}
|
||||
Out << 'E';
|
||||
return;
|
||||
break;
|
||||
}
|
||||
|
||||
case APValue::Array: {
|
||||
QualType ElemT(T->getArrayElementTypeNoTypeQual(), 0);
|
||||
|
||||
NotPrimaryExpr();
|
||||
Out << "tl";
|
||||
mangleType(T);
|
||||
|
||||
|
@ -5123,40 +5237,42 @@ void CXXNameMangler::mangleValueInTemplateArg(QualType T, const APValue &V) {
|
|||
const APValue &Elem = I < V.getArrayInitializedElts()
|
||||
? V.getArrayInitializedElt(I)
|
||||
: V.getArrayFiller();
|
||||
mangleValueInTemplateArg(ElemT, Elem);
|
||||
mangleValueInTemplateArg(ElemT, Elem, false);
|
||||
}
|
||||
Out << 'E';
|
||||
return;
|
||||
break;
|
||||
}
|
||||
|
||||
case APValue::Vector: {
|
||||
const VectorType *VT = T->castAs<VectorType>();
|
||||
|
||||
NotPrimaryExpr();
|
||||
Out << "tl";
|
||||
mangleType(T);
|
||||
unsigned N = V.getVectorLength();
|
||||
while (N && isZeroInitialized(VT->getElementType(), V.getVectorElt(N - 1)))
|
||||
--N;
|
||||
for (unsigned I = 0; I != N; ++I)
|
||||
mangleValueInTemplateArg(VT->getElementType(), V.getVectorElt(I));
|
||||
mangleValueInTemplateArg(VT->getElementType(), V.getVectorElt(I), false);
|
||||
Out << 'E';
|
||||
return;
|
||||
break;
|
||||
}
|
||||
|
||||
case APValue::Int:
|
||||
mangleIntegerLiteral(T, V.getInt());
|
||||
return;
|
||||
break;
|
||||
|
||||
case APValue::Float:
|
||||
mangleFloatLiteral(T, V.getFloat());
|
||||
return;
|
||||
break;
|
||||
|
||||
case APValue::FixedPoint:
|
||||
mangleFixedPointLiteral();
|
||||
return;
|
||||
break;
|
||||
|
||||
case APValue::ComplexFloat: {
|
||||
const ComplexType *CT = T->castAs<ComplexType>();
|
||||
NotPrimaryExpr();
|
||||
Out << "tl";
|
||||
mangleType(T);
|
||||
if (!V.getComplexFloatReal().isPosZero() ||
|
||||
|
@ -5165,11 +5281,12 @@ void CXXNameMangler::mangleValueInTemplateArg(QualType T, const APValue &V) {
|
|||
if (!V.getComplexFloatImag().isPosZero())
|
||||
mangleFloatLiteral(CT->getElementType(), V.getComplexFloatImag());
|
||||
Out << 'E';
|
||||
return;
|
||||
break;
|
||||
}
|
||||
|
||||
case APValue::ComplexInt: {
|
||||
const ComplexType *CT = T->castAs<ComplexType>();
|
||||
NotPrimaryExpr();
|
||||
Out << "tl";
|
||||
mangleType(T);
|
||||
if (V.getComplexIntReal().getBoolValue() ||
|
||||
|
@ -5178,7 +5295,7 @@ void CXXNameMangler::mangleValueInTemplateArg(QualType T, const APValue &V) {
|
|||
if (V.getComplexIntImag().getBoolValue())
|
||||
mangleIntegerLiteral(CT->getElementType(), V.getComplexIntImag());
|
||||
Out << 'E';
|
||||
return;
|
||||
break;
|
||||
}
|
||||
|
||||
case APValue::LValue: {
|
||||
|
@ -5188,7 +5305,7 @@ void CXXNameMangler::mangleValueInTemplateArg(QualType T, const APValue &V) {
|
|||
|
||||
if (V.isNullPointer()) {
|
||||
mangleNullPointer(T);
|
||||
return;
|
||||
break;
|
||||
}
|
||||
|
||||
APValue::LValueBase B = V.getLValueBase();
|
||||
|
@ -5199,54 +5316,82 @@ void CXXNameMangler::mangleValueInTemplateArg(QualType T, const APValue &V) {
|
|||
if (Offset.isZero()) {
|
||||
// This is reinterpret_cast<T*>(0), not a null pointer. Mangle this as
|
||||
// a cast, because L <type> 0 E means something else.
|
||||
NotPrimaryExpr();
|
||||
Out << "rc";
|
||||
mangleType(T);
|
||||
Out << "Li0E";
|
||||
if (TopLevel)
|
||||
Out << 'E';
|
||||
} else {
|
||||
Out << "L";
|
||||
mangleType(T);
|
||||
Out << Offset.getQuantity() << 'E';
|
||||
}
|
||||
return;
|
||||
break;
|
||||
}
|
||||
|
||||
ASTContext &Ctx = Context.getASTContext();
|
||||
|
||||
enum { Base, Offset, Path } Kind;
|
||||
if (!V.hasLValuePath()) {
|
||||
// Mangle as (T*)((char*)&base + N).
|
||||
if (T->isReferenceType()) {
|
||||
NotPrimaryExpr();
|
||||
Out << "decvP";
|
||||
mangleType(T->getPointeeType());
|
||||
} else {
|
||||
NotPrimaryExpr();
|
||||
Out << "cv";
|
||||
mangleType(T);
|
||||
}
|
||||
Out << "plcvPcad";
|
||||
Kind = Offset;
|
||||
} else {
|
||||
if (T->isPointerType())
|
||||
Out << "ad";
|
||||
if (!V.getLValuePath().empty() || V.isLValueOnePastTheEnd()) {
|
||||
NotPrimaryExpr();
|
||||
// A final conversion to the template parameter's type is usually
|
||||
// folded into the 'so' mangling, but we can't do that for 'void*'
|
||||
// parameters without introducing collisions.
|
||||
if (NeedExactType && T->isVoidPointerType()) {
|
||||
Out << "cv";
|
||||
mangleType(T);
|
||||
}
|
||||
if (T->isPointerType())
|
||||
Out << "ad";
|
||||
Out << "so";
|
||||
mangleType(T->getPointeeType());
|
||||
mangleType(T->isVoidPointerType()
|
||||
? getLValueType(Ctx, V).getUnqualifiedType()
|
||||
: T->getPointeeType());
|
||||
Kind = Path;
|
||||
} else {
|
||||
if (NeedExactType &&
|
||||
!Ctx.hasSameType(T->getPointeeType(), getLValueType(Ctx, V)) &&
|
||||
Ctx.getLangOpts().getClangABICompat() >
|
||||
LangOptions::ClangABI::Ver11) {
|
||||
NotPrimaryExpr();
|
||||
Out << "cv";
|
||||
mangleType(T);
|
||||
}
|
||||
if (T->isPointerType()) {
|
||||
NotPrimaryExpr();
|
||||
Out << "ad";
|
||||
}
|
||||
Kind = Base;
|
||||
}
|
||||
}
|
||||
|
||||
QualType TypeSoFar;
|
||||
QualType TypeSoFar = B.getType();
|
||||
if (auto *VD = B.dyn_cast<const ValueDecl*>()) {
|
||||
Out << 'L';
|
||||
mangle(VD);
|
||||
Out << 'E';
|
||||
TypeSoFar = VD->getType();
|
||||
} else if (auto *E = B.dyn_cast<const Expr*>()) {
|
||||
NotPrimaryExpr();
|
||||
mangleExpression(E);
|
||||
TypeSoFar = E->getType();
|
||||
} else if (auto TI = B.dyn_cast<TypeInfoLValue>()) {
|
||||
NotPrimaryExpr();
|
||||
Out << "ti";
|
||||
mangleType(QualType(TI.getType(), 0));
|
||||
TypeSoFar = B.getTypeInfoType();
|
||||
} else {
|
||||
// We should never see dynamic allocations here.
|
||||
llvm_unreachable("unexpected lvalue base kind in template argument");
|
||||
|
@ -5258,7 +5403,7 @@ void CXXNameMangler::mangleValueInTemplateArg(QualType T, const APValue &V) {
|
|||
|
||||
case Offset:
|
||||
Out << 'L';
|
||||
mangleType(Context.getASTContext().getPointerDiffType());
|
||||
mangleType(Ctx.getPointerDiffType());
|
||||
mangleNumber(V.getLValueOffset().getQuantity());
|
||||
Out << 'E';
|
||||
break;
|
||||
|
@ -5289,8 +5434,7 @@ void CXXNameMangler::mangleValueInTemplateArg(QualType T, const APValue &V) {
|
|||
}
|
||||
TypeSoFar = FD->getType();
|
||||
} else {
|
||||
TypeSoFar =
|
||||
Context.getASTContext().getRecordType(cast<CXXRecordDecl>(D));
|
||||
TypeSoFar = Ctx.getRecordType(cast<CXXRecordDecl>(D));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5301,19 +5445,30 @@ void CXXNameMangler::mangleValueInTemplateArg(QualType T, const APValue &V) {
|
|||
break;
|
||||
}
|
||||
|
||||
return;
|
||||
break;
|
||||
}
|
||||
|
||||
case APValue::MemberPointer:
|
||||
// Proposed in https://github.com/itanium-cxx-abi/cxx-abi/issues/47.
|
||||
if (!V.getMemberPointerDecl()) {
|
||||
mangleNullPointer(T);
|
||||
return;
|
||||
break;
|
||||
}
|
||||
|
||||
ASTContext &Ctx = Context.getASTContext();
|
||||
|
||||
NotPrimaryExpr();
|
||||
if (!V.getMemberPointerPath().empty()) {
|
||||
Out << "mc";
|
||||
mangleType(T);
|
||||
} else if (NeedExactType &&
|
||||
!Ctx.hasSameType(
|
||||
T->castAs<MemberPointerType>()->getPointeeType(),
|
||||
V.getMemberPointerDecl()->getType()) &&
|
||||
Ctx.getLangOpts().getClangABICompat() >
|
||||
LangOptions::ClangABI::Ver11) {
|
||||
Out << "cv";
|
||||
mangleType(T);
|
||||
}
|
||||
Out << "adL";
|
||||
mangle(V.getMemberPointerDecl());
|
||||
|
@ -5325,8 +5480,11 @@ void CXXNameMangler::mangleValueInTemplateArg(QualType T, const APValue &V) {
|
|||
mangleNumber(Offset.getQuantity());
|
||||
Out << 'E';
|
||||
}
|
||||
return;
|
||||
break;
|
||||
}
|
||||
|
||||
if (TopLevel && !IsPrimaryExpr)
|
||||
Out << 'E';
|
||||
}
|
||||
|
||||
void CXXNameMangler::mangleTemplateParameter(unsigned Depth, unsigned Index) {
|
||||
|
|
|
@ -2193,6 +2193,8 @@ void StmtProfiler::VisitTemplateArgument(const TemplateArgument &Arg) {
|
|||
break;
|
||||
|
||||
case TemplateArgument::Declaration:
|
||||
VisitType(Arg.getParamTypeForDecl());
|
||||
// FIXME: Do we need to recursively decompose template parameter objects?
|
||||
VisitDecl(Arg.getAsDecl());
|
||||
break;
|
||||
|
||||
|
@ -2201,8 +2203,8 @@ void StmtProfiler::VisitTemplateArgument(const TemplateArgument &Arg) {
|
|||
break;
|
||||
|
||||
case TemplateArgument::Integral:
|
||||
Arg.getAsIntegral().Profile(ID);
|
||||
VisitType(Arg.getIntegralType());
|
||||
Arg.getAsIntegral().Profile(ID);
|
||||
break;
|
||||
|
||||
case TemplateArgument::Expression:
|
||||
|
|
|
@ -244,6 +244,7 @@ void TemplateArgument::Profile(llvm::FoldingSetNodeID &ID,
|
|||
break;
|
||||
|
||||
case Declaration:
|
||||
getParamTypeForDecl().Profile(ID);
|
||||
ID.AddPointer(getAsDecl()? getAsDecl()->getCanonicalDecl() : nullptr);
|
||||
break;
|
||||
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
// RUN: %clang_cc1 -std=c++17 -triple x86_64-linux-gnu -fclang-abi-compat=3.0 %s -emit-llvm -o - | FileCheck --check-prefixes=PRE39,PRE5,PRE12 %s
|
||||
// RUN: %clang_cc1 -std=c++17 -triple x86_64-linux-gnu -fclang-abi-compat=3.8 %s -emit-llvm -o - | FileCheck --check-prefixes=PRE39,PRE5,PRE12 %s
|
||||
// RUN: %clang_cc1 -std=c++17 -triple x86_64-linux-gnu -fclang-abi-compat=3.9 %s -emit-llvm -o - | FileCheck --check-prefixes=V39,PRE5,PRE12 %s
|
||||
// RUN: %clang_cc1 -std=c++17 -triple x86_64-linux-gnu -fclang-abi-compat=4.0 %s -emit-llvm -o - | FileCheck --check-prefixes=V39,PRE5,PRE12 %s
|
||||
// RUN: %clang_cc1 -std=c++17 -triple x86_64-linux-gnu -fclang-abi-compat=5 %s -emit-llvm -o - | FileCheck --check-prefixes=V39,V5,PRE12 %s
|
||||
// RUN: %clang_cc1 -std=c++17 -triple x86_64-linux-gnu -fclang-abi-compat=11 %s -emit-llvm -o - | FileCheck --check-prefixes=V11,V5,PRE12 %s
|
||||
// RUN: %clang_cc1 -std=c++17 -triple x86_64-linux-gnu -fclang-abi-compat=latest %s -emit-llvm -o - | FileCheck --check-prefixes=V39,V5,V12 %s
|
||||
// RUN: %clang_cc1 -std=c++98 -triple x86_64-linux-gnu -fclang-abi-compat=3.0 %s -emit-llvm -o - | FileCheck --check-prefixes=CHECK,PRE39,PRE5,PRE12 %s
|
||||
// RUN: %clang_cc1 -std=c++17 -triple x86_64-linux-gnu -fclang-abi-compat=3.0 %s -emit-llvm -o - | FileCheck --check-prefixes=CHECK,PRE39,PRE5,PRE12 %s
|
||||
// RUN: %clang_cc1 -std=c++17 -triple x86_64-linux-gnu -fclang-abi-compat=3.8 %s -emit-llvm -o - | FileCheck --check-prefixes=CHECK,PRE39,PRE5,PRE12 %s
|
||||
// RUN: %clang_cc1 -std=c++17 -triple x86_64-linux-gnu -fclang-abi-compat=3.9 %s -emit-llvm -o - | FileCheck --check-prefixes=CHECK,V39,PRE5,PRE12 %s
|
||||
// RUN: %clang_cc1 -std=c++17 -triple x86_64-linux-gnu -fclang-abi-compat=4.0 %s -emit-llvm -o - | FileCheck --check-prefixes=CHECK,V39,PRE5,PRE12 %s
|
||||
// RUN: %clang_cc1 -std=c++17 -triple x86_64-linux-gnu -fclang-abi-compat=5 %s -emit-llvm -o - | FileCheck --check-prefixes=CHECK,V39,V5,PRE12,PRE12-CXX17 %s
|
||||
// RUN: %clang_cc1 -std=c++17 -triple x86_64-linux-gnu -fclang-abi-compat=11 %s -emit-llvm -o - | FileCheck --check-prefixes=CHECK,V39,V5,PRE12,PRE12-CXX17 %s
|
||||
// RUN: %clang_cc1 -std=c++98 -triple x86_64-linux-gnu -fclang-abi-compat=latest %s -emit-llvm -o - | FileCheck --check-prefixes=CHECK,V39,V5,V12 %s
|
||||
// RUN: %clang_cc1 -std=c++20 -triple x86_64-linux-gnu -fclang-abi-compat=latest %s -emit-llvm -o - | FileCheck --check-prefixes=CHECK,V39,V5,V12,V12-CXX17 %s
|
||||
|
||||
typedef __attribute__((vector_size(8))) long long v1xi64;
|
||||
void clang39(v1xi64) {}
|
||||
|
@ -27,3 +29,29 @@ namespace mangle_template_prefix {
|
|||
void g() { f<T>(1, 2); }
|
||||
}
|
||||
|
||||
int arg;
|
||||
template<const int *> struct clang12_unchanged {};
|
||||
// CHECK: @_Z4test17clang12_unchangedIXadL_Z3argEEE
|
||||
void test(clang12_unchanged<&arg>) {}
|
||||
|
||||
#if __cplusplus >= 201703L
|
||||
// PRE12-CXX17: @_Z4test15clang12_changedIXadL_Z3argEEE
|
||||
// V12-CXX17: @_Z4test15clang12_changedIXcvPKiadL_Z3argEEE
|
||||
template<auto> struct clang12_changed {};
|
||||
void test(clang12_changed<(const int*)&arg>) {}
|
||||
#endif
|
||||
|
||||
// PRE12: @_Z9clang12_aIXadL_Z3argEEEvv
|
||||
// V12: @_Z9clang12_aIXcvPKiadL_Z3argEEEvv
|
||||
template<const int *> void clang12_a() {}
|
||||
template void clang12_a<&arg>();
|
||||
|
||||
// PRE12: @_Z9clang12_bIXadL_Z3arrEEEvv
|
||||
// V12: @_Z9clang12_bIXadsoKcL_Z3arrEEEEvv
|
||||
extern const char arr[6] = "hello";
|
||||
template<const char *> void clang12_b() {}
|
||||
template void clang12_b<arr>();
|
||||
|
||||
// CHECK: @_Z9clang12_cIXadL_Z3arrEEEvv
|
||||
template<const char (*)[6]> void clang12_c() {}
|
||||
template void clang12_c<&arr>();
|
||||
|
|
|
@ -124,7 +124,7 @@ union E {
|
|||
template<E> void f() {}
|
||||
|
||||
// Union members.
|
||||
// CHECK: define weak_odr void @_Z1fIXL1EEEEvv(
|
||||
// CHECK: define weak_odr void @_Z1fIL1EEEvv(
|
||||
// MSABI: define {{.*}} @"??$f@$7TE@@@@@YAXXZ"
|
||||
template void f<E{}>();
|
||||
// CHECK: define weak_odr void @_Z1fIXtl1EEEEvv(
|
||||
|
@ -214,10 +214,10 @@ template<H1> void f() {}
|
|||
template<H2> void f() {}
|
||||
template<H3> void f() {}
|
||||
template<H4> void f() {}
|
||||
// CHECK: define weak_odr void @_Z1fIXL2H1EEEvv
|
||||
// CHECK: define weak_odr void @_Z1fIL2H1EEvv
|
||||
// MSABI: define {{.*}} @"??$f@$7TH1@@@@@YAXXZ"
|
||||
template void f<H1{}>();
|
||||
// CHECK: define weak_odr void @_Z1fIXL2H2EEEvv
|
||||
// CHECK: define weak_odr void @_Z1fIL2H2EEvv
|
||||
// MSABI: define {{.*}} @"??$f@$7TH2@@@@@YAXXZ"
|
||||
template void f<H2{}>();
|
||||
// CHECK: define weak_odr void @_Z1fIXtl2H3EEEvv
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
// RUN: %clang_cc1 -verify -Wno-return-type -Wno-main -std=c++11 -emit-llvm -triple %itanium_abi_triple -o - %s | FileCheck %s
|
||||
// RUN: %clang_cc1 -verify -Wno-return-type -Wno-main -std=c++20 -emit-llvm -triple x86_64-linux-gnu -o - %s | FileCheck %s --check-prefixes=CHECK,CXX20
|
||||
// expected-no-diagnostics
|
||||
|
||||
namespace test1 {
|
||||
|
@ -221,3 +222,115 @@ namespace test16 {
|
|||
void g() { f<T>(1, 2); }
|
||||
}
|
||||
|
||||
#if __cplusplus >= 202002L
|
||||
namespace cxx20 {
|
||||
template<auto> struct A {};
|
||||
template<typename T, T V> struct B {};
|
||||
|
||||
int x;
|
||||
// CXX20: define {{.*}} @_ZN5cxx201fENS_1AIXadL_ZNS_1xEEEEE(
|
||||
void f(A<&x>) {}
|
||||
// CXX20: define {{.*}} @_ZN5cxx201fENS_1BIPiXadL_ZNS_1xEEEEE(
|
||||
void f(B<int*, &x>) {}
|
||||
// CXX20: define {{.*}} @_ZN5cxx201fENS_1AIXcvPKiadL_ZNS_1xEEEEE(
|
||||
void f(A<(const int*)&x>) {}
|
||||
// CXX20: define {{.*}} @_ZN5cxx201fENS_1BIPKiXadL_ZNS_1xEEEEE(
|
||||
void f(B<const int*, &x>) {}
|
||||
// CXX20: define {{.*}} @_ZN5cxx201fENS_1AIXcvPvadL_ZNS_1xEEEEE(
|
||||
void f(A<(void*)&x>) {}
|
||||
// CXX20: define {{.*}} @_ZN5cxx201fENS_1BIPvXadL_ZNS_1xEEEEE(
|
||||
void f(B<void*, (void*)&x>) {}
|
||||
// CXX20: define {{.*}} @_ZN5cxx201fENS_1AIXcvPKvadL_ZNS_1xEEEEE(
|
||||
void f(A<(const void*)&x>) {}
|
||||
// CXX20: define {{.*}} @_ZN5cxx201fENS_1BIPKvXadL_ZNS_1xEEEEE(
|
||||
void f(B<const void*, (const void*)&x>) {}
|
||||
|
||||
struct Q { int x; };
|
||||
|
||||
// CXX20: define {{.*}} @_ZN5cxx201fENS_1AIXadL_ZNS_1Q1xEEEEE(
|
||||
void f(A<&Q::x>) {}
|
||||
// CXX20: define {{.*}} @_ZN5cxx201fENS_1BIMNS_1QEiXadL_ZNS1_1xEEEEE
|
||||
void f(B<int Q::*, &Q::x>) {}
|
||||
// CXX20: define {{.*}} @_ZN5cxx201fENS_1AIXcvMNS_1QEKiadL_ZNS1_1xEEEEE(
|
||||
void f(A<(const int Q::*)&Q::x>) {}
|
||||
// CXX20: define {{.*}} @_ZN5cxx201fENS_1BIMNS_1QEKiXadL_ZNS1_1xEEEEE(
|
||||
void f(B<const int Q::*, (const int Q::*)&Q::x>) {}
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace test17 {
|
||||
// Ensure we mangle the types for non-type template arguments if we've lost
|
||||
// track of argument / parameter correspondence.
|
||||
template<int A, int ...B> struct X {};
|
||||
|
||||
// CHECK: define {{.*}} @_ZN6test171fILi1EJLi2ELi3ELi4EEEEvNS_1XIXT_EJLi5EXspT0_ELi6EEEE
|
||||
template<int D, int ...C> void f(X<D, 5u, C..., 6u>) {}
|
||||
void g() { f<1, 2, 3, 4>({}); }
|
||||
|
||||
// Note: there is no J...E here, because we can't form a pack argument, and
|
||||
// the 5u and 6u are mangled with the original type 'j' (unsigned int) not
|
||||
// with the resolved type 'i' (signed int).
|
||||
// CHECK: define {{.*}} @_ZN6test171hILi4EJLi1ELi2ELi3EEEEvNS_1XIXspT0_EXLj5EEXT_EXLj6EEEE
|
||||
template<int D, int ...C> void h(X<C..., 5u, D, 6u>) {}
|
||||
void i() { h<4, 1, 2, 3>({}); }
|
||||
|
||||
#if __cplusplus >= 201402L
|
||||
template<int A, const volatile int*> struct Y {};
|
||||
int n;
|
||||
// Case 1: &n is a resolved template argument, with a known parameter:
|
||||
// mangled with no conversion.
|
||||
// CXX20: define {{.*}} @_ZN6test172j1ILi1EEEvNS_1YIXT_EXadL_ZNS_1nEEEEE
|
||||
template<int N> void j1(Y<N, (const int*)&n>) {}
|
||||
// Case 2: &n is an unresolved template argument, with an unknown
|
||||
// corresopnding parameter: mangled as the source expression.
|
||||
// CXX20: define {{.*}} @_ZN6test172j2IJLi1EEEEvNS_1YIXspT_EXcvPKiadL_ZNS_1nEEEEE
|
||||
template<int ...Ns> void j2(Y<Ns..., (const int*)&n>) {}
|
||||
// Case 3: &n is a resolved template argument, with a known parameter, but
|
||||
// for a template that can be overloaded on type: mangled with the parameter type.
|
||||
// CXX20: define {{.*}} @_ZN6test172j3ILi1EEEvDTplT_clL_ZNS_1yIXcvPVKiadL_ZNS_1nEEEEEivEEE
|
||||
template<const volatile int*> int y();
|
||||
template<int N> void j3(decltype(N + y<(const int*)&n>())) {}
|
||||
void k() {
|
||||
j1<1>(Y<1, &n>());
|
||||
j2<1>(Y<1, &n>());
|
||||
j3<1>(0);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
namespace partially_dependent_template_args {
|
||||
namespace test1 {
|
||||
template<bool B> struct enable { using type = int; };
|
||||
template<typename ...> struct and_ { static constexpr bool value = true; };
|
||||
template<typename T> inline typename enable<and_<T, T, T>::value>::type f(T) {}
|
||||
// FIXME: GCC and ICC form a J...E mangling for the pack here. Clang
|
||||
// doesn't do so when mangling an <unresolved-prefix>. It's not clear who's
|
||||
// right. See https://github.com/itanium-cxx-abi/cxx-abi/issues/113.
|
||||
// CHECK: @_ZN33partially_dependent_template_args5test11fIiEENS0_6enableIXsr4and_IT_S3_S3_EE5valueEE4typeES3_
|
||||
void g() { f(0); }
|
||||
}
|
||||
|
||||
namespace test2 {
|
||||
struct X { int n; };
|
||||
template<unsigned> int f(X);
|
||||
|
||||
template<typename T> void g1(decltype(f<0>(T()))) {}
|
||||
template<typename T> void g2(decltype(f<0>({}) + T())) {}
|
||||
template<typename T> void g3(decltype(f<0>(X{}) + T())) {}
|
||||
template<int N> void g4(decltype(f<0>(X{N})));
|
||||
|
||||
// The first of these mangles the unconverted argument Li0E because the
|
||||
// callee is unresolved, the rest mangle the converted argument Lj0E
|
||||
// because the callee is resolved.
|
||||
void h() {
|
||||
// CHECK: @_ZN33partially_dependent_template_args5test22g1INS0_1XEEEvDTcl1fIXLi0EEEcvT__EEE
|
||||
g1<X>({});
|
||||
// CHECK: @_ZN33partially_dependent_template_args5test22g2IiEEvDTplclL_ZNS0_1fILj0EEEiNS0_1XEEilEEcvT__EE
|
||||
g2<int>({});
|
||||
// CHECK: @_ZN33partially_dependent_template_args5test22g3IiEEvDTplclL_ZNS0_1fILj0EEEiNS0_1XEEtlS3_EEcvT__EE
|
||||
g3<int>({});
|
||||
// CHECK: @_ZN33partially_dependent_template_args5test22g4ILi0EEEvDTclL_ZNS0_1fILj0EEEiNS0_1XEEtlS3_T_EEE
|
||||
g4<0>({});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -187,6 +187,11 @@ namespace Auto {
|
|||
int &r = f(B<&a>());
|
||||
float &s = f(B<&b>());
|
||||
|
||||
void type_affects_identity(B<&a>) {}
|
||||
void type_affects_identity(B<(const int*)&a>) {}
|
||||
void type_affects_identity(B<(void*)&a>) {}
|
||||
void type_affects_identity(B<(const void*)&a>) {}
|
||||
|
||||
// pointers to members
|
||||
template<typename T, auto *T::*p> struct B<p> {};
|
||||
template<typename T, auto **T::*p> struct B<p> {};
|
||||
|
@ -198,6 +203,12 @@ namespace Auto {
|
|||
char &u = f(B<&X::p>());
|
||||
short &v = f(B<&X::pp>());
|
||||
|
||||
struct Y : X {};
|
||||
void type_affects_identity(B<&X::n>) {}
|
||||
void type_affects_identity(B<(int Y::*)&X::n>) {} // FIXME: expected-error {{sorry}}
|
||||
void type_affects_identity(B<(const int X::*)&X::n>) {}
|
||||
void type_affects_identity(B<(const int Y::*)&X::n>) {} // FIXME: expected-error {{sorry}}
|
||||
|
||||
// A case where we need to do auto-deduction, and check whether the
|
||||
// resulting dependent types match during partial ordering. These
|
||||
// templates are not ordered due to the mismatching function parameter.
|
||||
|
|
Loading…
Reference in New Issue