forked from OSchip/llvm-project
[c++20] For P0732R2 / P1907R1: Basic code generation and name
mangling support for non-type template parameters of class type and template parameter objects. The Itanium side of this follows the approach I proposed in https://github.com/itanium-cxx-abi/cxx-abi/issues/47 on 2020-09-06. The MSVC side of this was determined empirically by observing MSVC's output. Differential Revision: https://reviews.llvm.org/D89998
This commit is contained in:
parent
892605b449
commit
b637148ecb
|
@ -2298,6 +2298,10 @@ public:
|
|||
const ObjCImplementationDecl *ID,
|
||||
const ObjCIvarDecl *Ivar) const;
|
||||
|
||||
/// Find the 'this' offset for the member path in a pointer-to-member
|
||||
/// APValue.
|
||||
CharUnits getMemberPointerPathAdjustment(const APValue &MP) const;
|
||||
|
||||
bool isNearlyEmpty(const CXXRecordDecl *RD) const;
|
||||
|
||||
VTableContextBase *getVTableContext();
|
||||
|
|
|
@ -11,10 +11,12 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/AST/APValue.h"
|
||||
#include "Linkage.h"
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "clang/AST/CharUnits.h"
|
||||
#include "clang/AST/DeclCXX.h"
|
||||
#include "clang/AST/Expr.h"
|
||||
#include "clang/AST/ExprCXX.h"
|
||||
#include "clang/AST/Type.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
|
@ -977,3 +979,99 @@ void APValue::MakeMemberPointer(const ValueDecl *Member, bool IsDerivedMember,
|
|||
for (unsigned I = 0; I != Path.size(); ++I)
|
||||
InternalPath[I] = Path[I]->getCanonicalDecl();
|
||||
}
|
||||
|
||||
LinkageInfo LinkageComputer::getLVForValue(const APValue &V,
|
||||
LVComputationKind computation) {
|
||||
LinkageInfo LV = LinkageInfo::external();
|
||||
|
||||
auto MergeLV = [&](LinkageInfo MergeLV) {
|
||||
LV.merge(MergeLV);
|
||||
return LV.getLinkage() == InternalLinkage;
|
||||
};
|
||||
auto Merge = [&](const APValue &V) {
|
||||
return MergeLV(getLVForValue(V, computation));
|
||||
};
|
||||
|
||||
switch (V.getKind()) {
|
||||
case APValue::None:
|
||||
case APValue::Indeterminate:
|
||||
case APValue::Int:
|
||||
case APValue::Float:
|
||||
case APValue::FixedPoint:
|
||||
case APValue::ComplexInt:
|
||||
case APValue::ComplexFloat:
|
||||
case APValue::Vector:
|
||||
break;
|
||||
|
||||
case APValue::AddrLabelDiff:
|
||||
// Even for an inline function, it's not reasonable to treat a difference
|
||||
// between the addresses of labels as an external value.
|
||||
return LinkageInfo::internal();
|
||||
|
||||
case APValue::Struct: {
|
||||
for (unsigned I = 0, N = V.getStructNumBases(); I != N; ++I)
|
||||
if (Merge(V.getStructBase(I)))
|
||||
break;
|
||||
for (unsigned I = 0, N = V.getStructNumFields(); I != N; ++I)
|
||||
if (Merge(V.getStructField(I)))
|
||||
break;
|
||||
break;
|
||||
}
|
||||
|
||||
case APValue::Union:
|
||||
if (const auto *FD = V.getUnionField())
|
||||
Merge(V.getUnionValue());
|
||||
break;
|
||||
|
||||
case APValue::Array: {
|
||||
for (unsigned I = 0, N = V.getArrayInitializedElts(); I != N; ++I)
|
||||
if (Merge(V.getArrayInitializedElt(I)))
|
||||
break;
|
||||
if (V.hasArrayFiller())
|
||||
Merge(V.getArrayFiller());
|
||||
break;
|
||||
}
|
||||
|
||||
case APValue::LValue: {
|
||||
if (!V.getLValueBase()) {
|
||||
// Null or absolute address: this is external.
|
||||
} else if (const auto *VD =
|
||||
V.getLValueBase().dyn_cast<const ValueDecl *>()) {
|
||||
if (VD && MergeLV(getLVForDecl(VD, computation)))
|
||||
break;
|
||||
} else if (const auto TI = V.getLValueBase().dyn_cast<TypeInfoLValue>()) {
|
||||
if (MergeLV(getLVForType(*TI.getType(), computation)))
|
||||
break;
|
||||
} else if (const Expr *E = V.getLValueBase().dyn_cast<const Expr *>()) {
|
||||
// Almost all expression bases are internal. The exception is
|
||||
// lifetime-extended temporaries.
|
||||
// FIXME: These should be modeled as having the
|
||||
// LifetimeExtendedTemporaryDecl itself as the base.
|
||||
// FIXME: If we permit Objective-C object literals in template arguments,
|
||||
// they should not imply internal linkage.
|
||||
auto *MTE = dyn_cast<MaterializeTemporaryExpr>(E);
|
||||
if (!MTE || MTE->getStorageDuration() == SD_FullExpression)
|
||||
return LinkageInfo::internal();
|
||||
if (MergeLV(getLVForDecl(MTE->getExtendingDecl(), computation)))
|
||||
break;
|
||||
} else {
|
||||
assert(V.getLValueBase().is<DynamicAllocLValue>() &&
|
||||
"unexpected LValueBase kind");
|
||||
return LinkageInfo::internal();
|
||||
}
|
||||
// The lvalue path doesn't matter: pointers to all subobjects always have
|
||||
// the same visibility as pointers to the complete object.
|
||||
break;
|
||||
}
|
||||
|
||||
case APValue::MemberPointer:
|
||||
if (const NamedDecl *D = V.getMemberPointerDecl())
|
||||
MergeLV(getLVForDecl(D, computation));
|
||||
// Note that we could have a base-to-derived conversion here to a member of
|
||||
// a derived class with less linkage/visibility. That's covered by the
|
||||
// linkage and visibility of the value's type.
|
||||
break;
|
||||
}
|
||||
|
||||
return LV;
|
||||
}
|
||||
|
|
|
@ -2487,6 +2487,25 @@ CharUnits ASTContext::getOffsetOfBaseWithVBPtr(const CXXRecordDecl *RD) const {
|
|||
return Offset;
|
||||
}
|
||||
|
||||
CharUnits ASTContext::getMemberPointerPathAdjustment(const APValue &MP) const {
|
||||
const ValueDecl *MPD = MP.getMemberPointerDecl();
|
||||
CharUnits ThisAdjustment = CharUnits::Zero();
|
||||
ArrayRef<const CXXRecordDecl*> Path = MP.getMemberPointerPath();
|
||||
bool DerivedMember = MP.isMemberPointerToDerivedMember();
|
||||
const CXXRecordDecl *RD = cast<CXXRecordDecl>(MPD->getDeclContext());
|
||||
for (unsigned I = 0, N = Path.size(); I != N; ++I) {
|
||||
const CXXRecordDecl *Base = RD;
|
||||
const CXXRecordDecl *Derived = Path[I];
|
||||
if (DerivedMember)
|
||||
std::swap(Base, Derived);
|
||||
ThisAdjustment += getASTRecordLayout(Derived).getBaseClassOffset(Base);
|
||||
RD = Path[I];
|
||||
}
|
||||
if (DerivedMember)
|
||||
ThisAdjustment = -ThisAdjustment;
|
||||
return ThisAdjustment;
|
||||
}
|
||||
|
||||
/// DeepCollectObjCIvars -
|
||||
/// This routine first collects all declared, but not synthesized, ivars in
|
||||
/// super class and then collects all ivars, including those synthesized for
|
||||
|
|
|
@ -1395,6 +1395,15 @@ LinkageInfo LinkageComputer::computeLVForDecl(const NamedDecl *D,
|
|||
|
||||
break;
|
||||
}
|
||||
|
||||
case Decl::TemplateParamObject: {
|
||||
// The template parameter object can be referenced from anywhere its type
|
||||
// and value can be referenced.
|
||||
auto *TPO = cast<TemplateParamObjectDecl>(D);
|
||||
LinkageInfo LV = getLVForType(*TPO->getType(), computation);
|
||||
LV.merge(getLVForValue(TPO->getValue(), computation));
|
||||
return LV;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle linkage for namespace-scope names.
|
||||
|
|
|
@ -534,6 +534,10 @@ private:
|
|||
void mangleAArch64FixedSveVectorType(const DependentVectorType *T);
|
||||
|
||||
void mangleIntegerLiteral(QualType T, const llvm::APSInt &Value);
|
||||
void mangleFloatLiteral(QualType T, const llvm::APFloat &V);
|
||||
void mangleFixedPointLiteral();
|
||||
void mangleNullPointer(QualType T);
|
||||
|
||||
void mangleMemberExprBase(const Expr *base, bool isArrow);
|
||||
void mangleMemberExpr(const Expr *base, bool isArrow,
|
||||
NestedNameSpecifier *qualifier,
|
||||
|
@ -555,6 +559,7 @@ private:
|
|||
unsigned NumTemplateArgs);
|
||||
void mangleTemplateArgs(const TemplateArgumentList &AL);
|
||||
void mangleTemplateArg(TemplateArgument A);
|
||||
void mangleValueInTemplateArg(QualType T, const APValue &V);
|
||||
|
||||
void mangleTemplateParameter(unsigned Depth, unsigned Index);
|
||||
|
||||
|
@ -649,23 +654,13 @@ void CXXNameMangler::mangle(GlobalDecl GD) {
|
|||
Out << "_Z";
|
||||
if (isa<FunctionDecl>(GD.getDecl()))
|
||||
mangleFunctionEncoding(GD);
|
||||
else if (const VarDecl *VD = dyn_cast<VarDecl>(GD.getDecl()))
|
||||
mangleName(VD);
|
||||
else if (isa<VarDecl, FieldDecl, MSGuidDecl, TemplateParamObjectDecl,
|
||||
BindingDecl>(GD.getDecl()))
|
||||
mangleName(GD);
|
||||
else if (const IndirectFieldDecl *IFD =
|
||||
dyn_cast<IndirectFieldDecl>(GD.getDecl()))
|
||||
mangleName(IFD->getAnonField());
|
||||
else if (const FieldDecl *FD = dyn_cast<FieldDecl>(GD.getDecl()))
|
||||
mangleName(FD);
|
||||
else if (const MSGuidDecl *GuidD = dyn_cast<MSGuidDecl>(GD.getDecl()))
|
||||
mangleName(GuidD);
|
||||
else if (const BindingDecl *BD = dyn_cast<BindingDecl>(GD.getDecl()))
|
||||
mangleName(BD);
|
||||
else if (isa<TemplateParamObjectDecl>(GD.getDecl())) {
|
||||
DiagnosticsEngine &Diags = Context.getDiags();
|
||||
unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
|
||||
"cannot mangle template parameter objects yet");
|
||||
Diags.Report(SourceLocation(), DiagID);
|
||||
} else
|
||||
else
|
||||
llvm_unreachable("unexpected kind of global decl");
|
||||
}
|
||||
|
||||
|
@ -1064,6 +1059,27 @@ void CXXNameMangler::mangleFloat(const llvm::APFloat &f) {
|
|||
Out.write(buffer.data(), numCharacters);
|
||||
}
|
||||
|
||||
void CXXNameMangler::mangleFloatLiteral(QualType T, const llvm::APFloat &V) {
|
||||
Out << 'L';
|
||||
mangleType(T);
|
||||
mangleFloat(V);
|
||||
Out << 'E';
|
||||
}
|
||||
|
||||
void CXXNameMangler::mangleFixedPointLiteral() {
|
||||
DiagnosticsEngine &Diags = Context.getDiags();
|
||||
unsigned DiagID = Diags.getCustomDiagID(
|
||||
DiagnosticsEngine::Error, "cannot mangle fixed point literals yet");
|
||||
Diags.Report(DiagID);
|
||||
}
|
||||
|
||||
void CXXNameMangler::mangleNullPointer(QualType T) {
|
||||
// <expr-primary> ::= L <type> 0 E
|
||||
Out << 'L';
|
||||
mangleType(T);
|
||||
Out << "0E";
|
||||
}
|
||||
|
||||
void CXXNameMangler::mangleNumber(const llvm::APSInt &Value) {
|
||||
if (Value.isSigned() && Value.isNegative()) {
|
||||
Out << 'n';
|
||||
|
@ -1310,6 +1326,15 @@ void CXXNameMangler::mangleUnqualifiedName(GlobalDecl GD,
|
|||
break;
|
||||
}
|
||||
|
||||
if (auto *TPO = dyn_cast<TemplateParamObjectDecl>(ND)) {
|
||||
// Proposed in https://github.com/itanium-cxx-abi/cxx-abi/issues/63.
|
||||
Out << "TAX";
|
||||
mangleValueInTemplateArg(TPO->getType().getUnqualifiedType(),
|
||||
TPO->getValue());
|
||||
Out << "E";
|
||||
break;
|
||||
}
|
||||
|
||||
if (II) {
|
||||
// Match GCC's naming convention for internal linkage symbols, for
|
||||
// symbols that are not actually visible outside of this TU. GCC
|
||||
|
@ -3950,7 +3975,6 @@ recurse:
|
|||
case Expr::PseudoObjectExprClass:
|
||||
case Expr::AtomicExprClass:
|
||||
case Expr::SourceLocExprClass:
|
||||
case Expr::FixedPointLiteralClass:
|
||||
case Expr::BuiltinBitCastExprClass:
|
||||
{
|
||||
if (!NullOut) {
|
||||
|
@ -4524,13 +4548,14 @@ recurse:
|
|||
|
||||
case Expr::FloatingLiteralClass: {
|
||||
const FloatingLiteral *FL = cast<FloatingLiteral>(E);
|
||||
Out << 'L';
|
||||
mangleType(FL->getType());
|
||||
mangleFloat(FL->getValue());
|
||||
Out << 'E';
|
||||
mangleFloatLiteral(FL->getType(), FL->getValue());
|
||||
break;
|
||||
}
|
||||
|
||||
case Expr::FixedPointLiteralClass:
|
||||
mangleFixedPointLiteral();
|
||||
break;
|
||||
|
||||
case Expr::CharacterLiteralClass:
|
||||
Out << 'L';
|
||||
mangleType(E->getType());
|
||||
|
@ -4593,9 +4618,7 @@ recurse:
|
|||
|
||||
case Expr::GNUNullExprClass:
|
||||
// Mangle as if an integer literal 0.
|
||||
Out << 'L';
|
||||
mangleType(E->getType());
|
||||
Out << "0E";
|
||||
mangleIntegerLiteral(E->getType(), llvm::APSInt(32));
|
||||
break;
|
||||
|
||||
case Expr::CXXNullPtrLiteralExprClass: {
|
||||
|
@ -4876,21 +4899,29 @@ void CXXNameMangler::mangleTemplateArg(TemplateArgument A) {
|
|||
break;
|
||||
case TemplateArgument::Declaration: {
|
||||
// <expr-primary> ::= L <mangled-name> E # external name
|
||||
ValueDecl *D = A.getAsDecl();
|
||||
|
||||
// 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';
|
||||
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.
|
||||
ValueDecl *D = A.getAsDecl();
|
||||
bool compensateMangling = !A.getParamTypeForDecl()->isReferenceType();
|
||||
if (compensateMangling) {
|
||||
Out << 'X';
|
||||
mangleOperatorName(OO_Amp, 1);
|
||||
}
|
||||
|
||||
Out << 'L';
|
||||
// References to external entities use the mangled name; if the name would
|
||||
// not normally be mangled then mangle it as unqualified.
|
||||
mangle(D);
|
||||
Out << 'E';
|
||||
mangleDeclRefExpr(D);
|
||||
|
||||
if (compensateMangling)
|
||||
Out << 'E';
|
||||
|
@ -4898,10 +4929,7 @@ void CXXNameMangler::mangleTemplateArg(TemplateArgument A) {
|
|||
break;
|
||||
}
|
||||
case TemplateArgument::NullPtr: {
|
||||
// <expr-primary> ::= L <type> 0 E
|
||||
Out << 'L';
|
||||
mangleType(A.getNullPtrType());
|
||||
Out << "0E";
|
||||
mangleNullPointer(A.getNullPtrType());
|
||||
break;
|
||||
}
|
||||
case TemplateArgument::Pack: {
|
||||
|
@ -4914,6 +4942,396 @@ void CXXNameMangler::mangleTemplateArg(TemplateArgument A) {
|
|||
}
|
||||
}
|
||||
|
||||
/// Determine whether a given value is equivalent to zero-initialization for
|
||||
/// the purpose of discarding a trailing portion of a 'tl' mangling.
|
||||
///
|
||||
/// Note that this is not in general equivalent to determining whether the
|
||||
/// value has an all-zeroes bit pattern.
|
||||
static bool isZeroInitialized(QualType T, const APValue &V) {
|
||||
// FIXME: mangleValueInTemplateArg has quadratic time complexity in
|
||||
// pathological cases due to using this, but it's a little awkward
|
||||
// to do this in linear time in general.
|
||||
switch (V.getKind()) {
|
||||
case APValue::None:
|
||||
case APValue::Indeterminate:
|
||||
case APValue::AddrLabelDiff:
|
||||
return false;
|
||||
|
||||
case APValue::Struct: {
|
||||
const CXXRecordDecl *RD = T->getAsCXXRecordDecl();
|
||||
assert(RD && "unexpected type for record value");
|
||||
unsigned I = 0;
|
||||
for (const CXXBaseSpecifier &BS : RD->bases()) {
|
||||
if (!isZeroInitialized(BS.getType(), V.getStructBase(I)))
|
||||
return false;
|
||||
++I;
|
||||
}
|
||||
I = 0;
|
||||
for (const FieldDecl *FD : RD->fields()) {
|
||||
if (!FD->isUnnamedBitfield() &&
|
||||
!isZeroInitialized(FD->getType(), V.getStructField(I)))
|
||||
return false;
|
||||
++I;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
case APValue::Union: {
|
||||
const CXXRecordDecl *RD = T->getAsCXXRecordDecl();
|
||||
assert(RD && "unexpected type for union value");
|
||||
// Zero-initialization zeroes the first non-unnamed-bitfield field, if any.
|
||||
for (const FieldDecl *FD : RD->fields()) {
|
||||
if (!FD->isUnnamedBitfield())
|
||||
return V.getUnionField() && declaresSameEntity(FD, V.getUnionField()) &&
|
||||
isZeroInitialized(FD->getType(), V.getUnionValue());
|
||||
}
|
||||
// If there are no fields (other than unnamed bitfields), the value is
|
||||
// necessarily zero-initialized.
|
||||
return true;
|
||||
}
|
||||
|
||||
case APValue::Array: {
|
||||
QualType ElemT(T->getArrayElementTypeNoTypeQual(), 0);
|
||||
for (unsigned I = 0, N = V.getArrayInitializedElts(); I != N; ++I)
|
||||
if (!isZeroInitialized(ElemT, V.getArrayInitializedElt(I)))
|
||||
return false;
|
||||
return !V.hasArrayFiller() || isZeroInitialized(ElemT, V.getArrayFiller());
|
||||
}
|
||||
|
||||
case APValue::Vector: {
|
||||
const VectorType *VT = T->castAs<VectorType>();
|
||||
for (unsigned I = 0, N = V.getVectorLength(); I != N; ++I)
|
||||
if (!isZeroInitialized(VT->getElementType(), V.getVectorElt(I)))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
case APValue::Int:
|
||||
return !V.getInt();
|
||||
|
||||
case APValue::Float:
|
||||
return V.getFloat().isPosZero();
|
||||
|
||||
case APValue::FixedPoint:
|
||||
return !V.getFixedPoint().getValue();
|
||||
|
||||
case APValue::ComplexFloat:
|
||||
return V.getComplexFloatReal().isPosZero() &&
|
||||
V.getComplexFloatImag().isPosZero();
|
||||
|
||||
case APValue::ComplexInt:
|
||||
return !V.getComplexIntReal() && !V.getComplexIntImag();
|
||||
|
||||
case APValue::LValue:
|
||||
return V.isNullPointer();
|
||||
|
||||
case APValue::MemberPointer:
|
||||
return !V.getMemberPointerDecl();
|
||||
}
|
||||
}
|
||||
|
||||
void CXXNameMangler::mangleValueInTemplateArg(QualType T, const APValue &V) {
|
||||
// Ignore all top-level cv-qualifiers, to match GCC.
|
||||
Qualifiers Quals;
|
||||
T = getASTContext().getUnqualifiedArrayType(T, Quals);
|
||||
|
||||
// Proposed in https://github.com/itanium-cxx-abi/cxx-abi/issues/63.
|
||||
switch (V.getKind()) {
|
||||
case APValue::None:
|
||||
case APValue::Indeterminate:
|
||||
Out << 'L';
|
||||
mangleType(T);
|
||||
Out << 'E';
|
||||
return;
|
||||
|
||||
case APValue::AddrLabelDiff:
|
||||
llvm_unreachable("unexpected value kind in template argument");
|
||||
|
||||
case APValue::Struct: {
|
||||
const CXXRecordDecl *RD = T->getAsCXXRecordDecl();
|
||||
assert(RD && "unexpected type for record value");
|
||||
|
||||
// Drop trailing zero-initialized elements.
|
||||
llvm::SmallVector<const FieldDecl *, 16> Fields(RD->field_begin(),
|
||||
RD->field_end());
|
||||
while (
|
||||
!Fields.empty() &&
|
||||
(Fields.back()->isUnnamedBitfield() ||
|
||||
isZeroInitialized(Fields.back()->getType(),
|
||||
V.getStructField(Fields.back()->getFieldIndex())))) {
|
||||
Fields.pop_back();
|
||||
}
|
||||
llvm::ArrayRef<CXXBaseSpecifier> Bases(RD->bases_begin(), RD->bases_end());
|
||||
if (Fields.empty()) {
|
||||
while (!Bases.empty() &&
|
||||
isZeroInitialized(Bases.back().getType(),
|
||||
V.getStructBase(Bases.size() - 1)))
|
||||
Bases = Bases.drop_back();
|
||||
}
|
||||
|
||||
// <expression> ::= tl <type> <braced-expression>* E
|
||||
Out << "tl";
|
||||
mangleType(T);
|
||||
for (unsigned I = 0, N = Bases.size(); I != N; ++I)
|
||||
mangleValueInTemplateArg(Bases[I].getType(), V.getStructBase(I));
|
||||
for (unsigned I = 0, N = Fields.size(); I != N; ++I) {
|
||||
if (Fields[I]->isUnnamedBitfield())
|
||||
continue;
|
||||
mangleValueInTemplateArg(Fields[I]->getType(),
|
||||
V.getStructField(Fields[I]->getFieldIndex()));
|
||||
}
|
||||
Out << 'E';
|
||||
return;
|
||||
}
|
||||
|
||||
case APValue::Union: {
|
||||
const CXXRecordDecl *RD = T->getAsCXXRecordDecl();
|
||||
assert(RD && "unexpected type for union value");
|
||||
const FieldDecl *FD = V.getUnionField();
|
||||
|
||||
if (!FD) {
|
||||
Out << 'L';
|
||||
mangleType(T);
|
||||
Out << 'E';
|
||||
return;
|
||||
}
|
||||
|
||||
// <braced-expression> ::= di <field source-name> <braced-expression>
|
||||
Out << "tl";
|
||||
mangleType(T);
|
||||
if (!isZeroInitialized(T, V)) {
|
||||
Out << "di";
|
||||
mangleSourceName(FD->getIdentifier());
|
||||
mangleValueInTemplateArg(FD->getType(), V.getUnionValue());
|
||||
}
|
||||
Out << 'E';
|
||||
return;
|
||||
}
|
||||
|
||||
case APValue::Array: {
|
||||
QualType ElemT(T->getArrayElementTypeNoTypeQual(), 0);
|
||||
|
||||
Out << "tl";
|
||||
mangleType(T);
|
||||
|
||||
// Drop trailing zero-initialized elements.
|
||||
unsigned N = V.getArraySize();
|
||||
if (!V.hasArrayFiller() || isZeroInitialized(ElemT, V.getArrayFiller())) {
|
||||
N = V.getArrayInitializedElts();
|
||||
while (N && isZeroInitialized(ElemT, V.getArrayInitializedElt(N - 1)))
|
||||
--N;
|
||||
}
|
||||
|
||||
for (unsigned I = 0; I != N; ++I) {
|
||||
const APValue &Elem = I < V.getArrayInitializedElts()
|
||||
? V.getArrayInitializedElt(I)
|
||||
: V.getArrayFiller();
|
||||
mangleValueInTemplateArg(ElemT, Elem);
|
||||
}
|
||||
Out << 'E';
|
||||
return;
|
||||
}
|
||||
|
||||
case APValue::Vector: {
|
||||
const VectorType *VT = T->castAs<VectorType>();
|
||||
|
||||
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));
|
||||
Out << 'E';
|
||||
return;
|
||||
}
|
||||
|
||||
case APValue::Int:
|
||||
mangleIntegerLiteral(T, V.getInt());
|
||||
return;
|
||||
|
||||
case APValue::Float:
|
||||
mangleFloatLiteral(T, V.getFloat());
|
||||
return;
|
||||
|
||||
case APValue::FixedPoint:
|
||||
mangleFixedPointLiteral();
|
||||
return;
|
||||
|
||||
case APValue::ComplexFloat: {
|
||||
const ComplexType *CT = T->castAs<ComplexType>();
|
||||
Out << "tl";
|
||||
mangleType(T);
|
||||
if (!V.getComplexFloatReal().isPosZero() ||
|
||||
!V.getComplexFloatImag().isPosZero())
|
||||
mangleFloatLiteral(CT->getElementType(), V.getComplexFloatReal());
|
||||
if (!V.getComplexFloatImag().isPosZero())
|
||||
mangleFloatLiteral(CT->getElementType(), V.getComplexFloatImag());
|
||||
Out << 'E';
|
||||
return;
|
||||
}
|
||||
|
||||
case APValue::ComplexInt: {
|
||||
const ComplexType *CT = T->castAs<ComplexType>();
|
||||
Out << "tl";
|
||||
mangleType(T);
|
||||
if (V.getComplexIntReal().getBoolValue() ||
|
||||
V.getComplexIntImag().getBoolValue())
|
||||
mangleIntegerLiteral(CT->getElementType(), V.getComplexIntReal());
|
||||
if (V.getComplexIntImag().getBoolValue())
|
||||
mangleIntegerLiteral(CT->getElementType(), V.getComplexIntImag());
|
||||
Out << 'E';
|
||||
return;
|
||||
}
|
||||
|
||||
case APValue::LValue: {
|
||||
// Proposed in https://github.com/itanium-cxx-abi/cxx-abi/issues/47.
|
||||
assert((T->isPointerType() || T->isReferenceType()) &&
|
||||
"unexpected type for LValue template arg");
|
||||
|
||||
if (V.isNullPointer()) {
|
||||
mangleNullPointer(T);
|
||||
return;
|
||||
}
|
||||
|
||||
APValue::LValueBase B = V.getLValueBase();
|
||||
if (!B) {
|
||||
// Non-standard mangling for integer cast to a pointer; this can only
|
||||
// occur as an extension.
|
||||
CharUnits Offset = V.getLValueOffset();
|
||||
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.
|
||||
Out << "rc";
|
||||
mangleType(T);
|
||||
Out << "Li0E";
|
||||
} else {
|
||||
Out << "L";
|
||||
mangleType(T);
|
||||
Out << Offset.getQuantity() << 'E';
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
enum { Base, Offset, Path } Kind;
|
||||
if (!V.hasLValuePath()) {
|
||||
// Mangle as (T*)((char*)&base + N).
|
||||
if (T->isReferenceType()) {
|
||||
Out << "decvP";
|
||||
mangleType(T->getPointeeType());
|
||||
} else {
|
||||
Out << "cv";
|
||||
mangleType(T);
|
||||
}
|
||||
Out << "plcvPcad";
|
||||
Kind = Offset;
|
||||
} else {
|
||||
if (T->isPointerType())
|
||||
Out << "ad";
|
||||
if (!V.getLValuePath().empty() || V.isLValueOnePastTheEnd()) {
|
||||
Out << "so";
|
||||
mangleType(T->getPointeeType());
|
||||
Kind = Path;
|
||||
} else {
|
||||
Kind = Base;
|
||||
}
|
||||
}
|
||||
|
||||
QualType TypeSoFar;
|
||||
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*>()) {
|
||||
mangleExpression(E);
|
||||
TypeSoFar = E->getType();
|
||||
} else if (auto TI = B.dyn_cast<TypeInfoLValue>()) {
|
||||
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");
|
||||
}
|
||||
|
||||
switch (Kind) {
|
||||
case Base:
|
||||
break;
|
||||
|
||||
case Offset:
|
||||
Out << 'L';
|
||||
mangleType(Context.getASTContext().getPointerDiffType());
|
||||
mangleNumber(V.getLValueOffset().getQuantity());
|
||||
Out << 'E';
|
||||
break;
|
||||
|
||||
case Path:
|
||||
// <expression> ::= so <referent type> <expr> [<offset number>]
|
||||
// <union-selector>* [p] E
|
||||
if (!V.getLValueOffset().isZero())
|
||||
mangleNumber(V.getLValueOffset().getQuantity());
|
||||
|
||||
// We model a past-the-end array pointer as array indexing with index N,
|
||||
// not with the "past the end" flag. Compensate for that.
|
||||
bool OnePastTheEnd = V.isLValueOnePastTheEnd();
|
||||
|
||||
for (APValue::LValuePathEntry E : V.getLValuePath()) {
|
||||
if (auto *AT = TypeSoFar->getAsArrayTypeUnsafe()) {
|
||||
if (auto *CAT = dyn_cast<ConstantArrayType>(AT))
|
||||
OnePastTheEnd |= CAT->getSize() == E.getAsArrayIndex();
|
||||
TypeSoFar = AT->getElementType();
|
||||
} else {
|
||||
const Decl *D = E.getAsBaseOrMember().getPointer();
|
||||
if (auto *FD = dyn_cast<FieldDecl>(D)) {
|
||||
// <union-selector> ::= _ <number>
|
||||
if (FD->getParent()->isUnion()) {
|
||||
Out << '_';
|
||||
if (FD->getFieldIndex())
|
||||
Out << (FD->getFieldIndex() - 1);
|
||||
}
|
||||
TypeSoFar = FD->getType();
|
||||
} else {
|
||||
TypeSoFar =
|
||||
Context.getASTContext().getRecordType(cast<CXXRecordDecl>(D));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (OnePastTheEnd)
|
||||
Out << 'p';
|
||||
Out << 'E';
|
||||
break;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
case APValue::MemberPointer:
|
||||
// Proposed in https://github.com/itanium-cxx-abi/cxx-abi/issues/47.
|
||||
if (!V.getMemberPointerDecl()) {
|
||||
mangleNullPointer(T);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!V.getMemberPointerPath().empty()) {
|
||||
Out << "mc";
|
||||
mangleType(T);
|
||||
}
|
||||
Out << "adL";
|
||||
mangle(V.getMemberPointerDecl());
|
||||
Out << 'E';
|
||||
if (!V.getMemberPointerPath().empty()) {
|
||||
CharUnits Offset =
|
||||
Context.getASTContext().getMemberPointerPathAdjustment(V);
|
||||
if (!Offset.isZero())
|
||||
mangleNumber(Offset.getQuantity());
|
||||
Out << 'E';
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void CXXNameMangler::mangleTemplateParameter(unsigned Depth, unsigned Index) {
|
||||
// <template-param> ::= T_ # first template parameter
|
||||
// ::= T <parameter-2 non-negative number> _
|
||||
|
@ -5230,8 +5648,8 @@ bool CXXNameMangler::shouldHaveAbiTags(ItaniumMangleContextImpl &C,
|
|||
void ItaniumMangleContextImpl::mangleCXXName(GlobalDecl GD,
|
||||
raw_ostream &Out) {
|
||||
const NamedDecl *D = cast<NamedDecl>(GD.getDecl());
|
||||
assert((isa<FunctionDecl>(D) || isa<VarDecl>(D)) &&
|
||||
"Invalid mangleName() call, argument is not a variable or function!");
|
||||
assert((isa<FunctionDecl, VarDecl, TemplateParamObjectDecl>(D)) &&
|
||||
"Invalid mangleName() call, argument is not a variable or function!");
|
||||
|
||||
PrettyStackTraceDecl CrashInfo(D, SourceLocation(),
|
||||
getASTContext().getSourceManager(),
|
||||
|
|
|
@ -140,6 +140,8 @@ class LinkageComputer {
|
|||
LinkageInfo getLVForTemplateParameterList(const TemplateParameterList *Params,
|
||||
LVComputationKind computation);
|
||||
|
||||
LinkageInfo getLVForValue(const APValue &V, LVComputationKind computation);
|
||||
|
||||
public:
|
||||
LinkageInfo computeLVForDecl(const NamedDecl *D,
|
||||
LVComputationKind computation,
|
||||
|
|
|
@ -308,12 +308,17 @@ public:
|
|||
void mangleName(const NamedDecl *ND);
|
||||
void mangleFunctionEncoding(const FunctionDecl *FD, bool ShouldMangle);
|
||||
void mangleVariableEncoding(const VarDecl *VD);
|
||||
void mangleMemberDataPointer(const CXXRecordDecl *RD, const ValueDecl *VD);
|
||||
void mangleMemberDataPointer(const CXXRecordDecl *RD, const ValueDecl *VD,
|
||||
StringRef Prefix = "$");
|
||||
void mangleMemberFunctionPointer(const CXXRecordDecl *RD,
|
||||
const CXXMethodDecl *MD);
|
||||
const CXXMethodDecl *MD,
|
||||
StringRef Prefix = "$");
|
||||
void mangleVirtualMemPtrThunk(const CXXMethodDecl *MD,
|
||||
const MethodVFTableLocation &ML);
|
||||
void mangleNumber(int64_t Number);
|
||||
void mangleNumber(llvm::APSInt Number);
|
||||
void mangleFloat(llvm::APFloat Number);
|
||||
void mangleBits(llvm::APInt Number);
|
||||
void mangleTagTypeKind(TagTypeKind TK);
|
||||
void mangleArtificialTagType(TagTypeKind TK, StringRef UnqualifiedName,
|
||||
ArrayRef<StringRef> NestedNames = None);
|
||||
|
@ -388,6 +393,8 @@ private:
|
|||
const TemplateArgumentList &TemplateArgs);
|
||||
void mangleTemplateArg(const TemplateDecl *TD, const TemplateArgument &TA,
|
||||
const NamedDecl *Parm);
|
||||
void mangleTemplateArgValue(QualType T, const APValue &V,
|
||||
bool WithScalarType = true);
|
||||
|
||||
void mangleObjCProtocol(const ObjCProtocolDecl *PD);
|
||||
void mangleObjCLifetime(const QualType T, Qualifiers Quals,
|
||||
|
@ -504,10 +511,8 @@ void MicrosoftCXXNameMangler::mangle(const NamedDecl *D, StringRef Prefix) {
|
|||
// 'const struct __s_GUID'.
|
||||
Out << "3U__s_GUID@@B";
|
||||
else if (isa<TemplateParamObjectDecl>(D)) {
|
||||
DiagnosticsEngine &Diags = Context.getDiags();
|
||||
unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
|
||||
"cannot mangle template parameter objects yet");
|
||||
Diags.Report(SourceLocation(), DiagID);
|
||||
// Template parameter objects don't get a <type-encoding>; their type is
|
||||
// specified as part of their value.
|
||||
} else
|
||||
llvm_unreachable("Tried to mangle unexpected NamedDecl!");
|
||||
}
|
||||
|
@ -599,7 +604,8 @@ void MicrosoftCXXNameMangler::mangleVariableEncoding(const VarDecl *VD) {
|
|||
}
|
||||
|
||||
void MicrosoftCXXNameMangler::mangleMemberDataPointer(const CXXRecordDecl *RD,
|
||||
const ValueDecl *VD) {
|
||||
const ValueDecl *VD,
|
||||
StringRef Prefix) {
|
||||
// <member-data-pointer> ::= <integer-literal>
|
||||
// ::= $F <number> <number>
|
||||
// ::= $G <number> <number> <number>
|
||||
|
@ -631,7 +637,7 @@ void MicrosoftCXXNameMangler::mangleMemberDataPointer(const CXXRecordDecl *RD,
|
|||
case MSInheritanceModel::Unspecified: Code = 'G'; break;
|
||||
}
|
||||
|
||||
Out << '$' << Code;
|
||||
Out << Prefix << Code;
|
||||
|
||||
mangleNumber(FieldOffset);
|
||||
|
||||
|
@ -646,7 +652,8 @@ void MicrosoftCXXNameMangler::mangleMemberDataPointer(const CXXRecordDecl *RD,
|
|||
|
||||
void
|
||||
MicrosoftCXXNameMangler::mangleMemberFunctionPointer(const CXXRecordDecl *RD,
|
||||
const CXXMethodDecl *MD) {
|
||||
const CXXMethodDecl *MD,
|
||||
StringRef Prefix) {
|
||||
// <member-function-pointer> ::= $1? <name>
|
||||
// ::= $H? <name> <number>
|
||||
// ::= $I? <name> <number> <number>
|
||||
|
@ -668,7 +675,7 @@ MicrosoftCXXNameMangler::mangleMemberFunctionPointer(const CXXRecordDecl *RD,
|
|||
uint64_t VBTableOffset = 0;
|
||||
uint64_t VBPtrOffset = 0;
|
||||
if (MD) {
|
||||
Out << '$' << Code << '?';
|
||||
Out << Prefix << Code << '?';
|
||||
if (MD->isVirtual()) {
|
||||
MicrosoftVTableContext *VTContext =
|
||||
cast<MicrosoftVTableContext>(getASTContext().getVTableContext());
|
||||
|
@ -691,12 +698,12 @@ MicrosoftCXXNameMangler::mangleMemberFunctionPointer(const CXXRecordDecl *RD,
|
|||
} else {
|
||||
// Null single inheritance member functions are encoded as a simple nullptr.
|
||||
if (IM == MSInheritanceModel::Single) {
|
||||
Out << "$0A@";
|
||||
Out << Prefix << "0A@";
|
||||
return;
|
||||
}
|
||||
if (IM == MSInheritanceModel::Unspecified)
|
||||
VBTableOffset = -1;
|
||||
Out << '$' << Code;
|
||||
Out << Prefix << Code;
|
||||
}
|
||||
|
||||
if (inheritanceModelHasNVOffsetField(/*IsMemberFunction=*/true, IM))
|
||||
|
@ -735,32 +742,63 @@ void MicrosoftCXXNameMangler::mangleName(const NamedDecl *ND) {
|
|||
}
|
||||
|
||||
void MicrosoftCXXNameMangler::mangleNumber(int64_t Number) {
|
||||
mangleNumber(llvm::APSInt(llvm::APInt(64, Number), /*IsUnsigned*/false));
|
||||
}
|
||||
|
||||
void MicrosoftCXXNameMangler::mangleNumber(llvm::APSInt Number) {
|
||||
// MSVC never mangles any integer wider than 64 bits. In general it appears
|
||||
// to convert every integer to signed 64 bit before mangling (including
|
||||
// unsigned 64 bit values). Do the same, but preserve bits beyond the bottom
|
||||
// 64.
|
||||
llvm::APInt Value =
|
||||
Number.isSigned() ? Number.sextOrSelf(64) : Number.zextOrSelf(64);
|
||||
|
||||
// <non-negative integer> ::= A@ # when Number == 0
|
||||
// ::= <decimal digit> # when 1 <= Number <= 10
|
||||
// ::= <hex digit>+ @ # when Number >= 10
|
||||
//
|
||||
// <number> ::= [?] <non-negative integer>
|
||||
|
||||
uint64_t Value = static_cast<uint64_t>(Number);
|
||||
if (Number < 0) {
|
||||
if (Value.isNegative()) {
|
||||
Value = -Value;
|
||||
Out << '?';
|
||||
}
|
||||
mangleBits(Value);
|
||||
}
|
||||
|
||||
void MicrosoftCXXNameMangler::mangleFloat(llvm::APFloat Number) {
|
||||
using llvm::APFloat;
|
||||
|
||||
switch (APFloat::SemanticsToEnum(Number.getSemantics())) {
|
||||
case APFloat::S_IEEEsingle: Out << 'A'; break;
|
||||
case APFloat::S_IEEEdouble: Out << 'B'; break;
|
||||
|
||||
// The following are all Clang extensions. We try to pick manglings that are
|
||||
// unlikely to conflict with MSVC's scheme.
|
||||
case APFloat::S_IEEEhalf: Out << 'V'; break;
|
||||
case APFloat::S_BFloat: Out << 'W'; break;
|
||||
case APFloat::S_x87DoubleExtended: Out << 'X'; break;
|
||||
case APFloat::S_IEEEquad: Out << 'Y'; break;
|
||||
case APFloat::S_PPCDoubleDouble: Out << 'Z'; break;
|
||||
}
|
||||
|
||||
mangleBits(Number.bitcastToAPInt());
|
||||
}
|
||||
|
||||
void MicrosoftCXXNameMangler::mangleBits(llvm::APInt Value) {
|
||||
if (Value == 0)
|
||||
Out << "A@";
|
||||
else if (Value >= 1 && Value <= 10)
|
||||
else if (Value.uge(1) && Value.ule(10))
|
||||
Out << (Value - 1);
|
||||
else {
|
||||
// Numbers that are not encoded as decimal digits are represented as nibbles
|
||||
// in the range of ASCII characters 'A' to 'P'.
|
||||
// The number 0x123450 would be encoded as 'BCDEFA'
|
||||
char EncodedNumberBuffer[sizeof(uint64_t) * 2];
|
||||
MutableArrayRef<char> BufferRef(EncodedNumberBuffer);
|
||||
MutableArrayRef<char>::reverse_iterator I = BufferRef.rbegin();
|
||||
for (; Value != 0; Value >>= 4)
|
||||
*I++ = 'A' + (Value & 0xf);
|
||||
Out.write(I.base(), I - BufferRef.rbegin());
|
||||
llvm::SmallString<32> EncodedNumberBuffer;
|
||||
for (; Value != 0; Value.lshrInPlace(4))
|
||||
EncodedNumberBuffer.push_back('A' + (Value & 0xf).getZExtValue());
|
||||
std::reverse(EncodedNumberBuffer.begin(), EncodedNumberBuffer.end());
|
||||
Out.write(EncodedNumberBuffer.data(), EncodedNumberBuffer.size());
|
||||
Out << '@';
|
||||
}
|
||||
}
|
||||
|
@ -914,6 +952,13 @@ void MicrosoftCXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
|
|||
break;
|
||||
}
|
||||
|
||||
if (const auto *TPO = dyn_cast<TemplateParamObjectDecl>(ND)) {
|
||||
Out << "?__N";
|
||||
mangleTemplateArgValue(TPO->getType().getUnqualifiedType(),
|
||||
TPO->getValue());
|
||||
break;
|
||||
}
|
||||
|
||||
// We must have an anonymous struct.
|
||||
const TagDecl *TD = cast<TagDecl>(ND);
|
||||
if (const TypedefNameDecl *D = TD->getTypedefNameForAnonDecl()) {
|
||||
|
@ -1382,10 +1427,7 @@ void MicrosoftCXXNameMangler::mangleIntegerLiteral(
|
|||
|
||||
Out << "0";
|
||||
|
||||
if (Value.isSigned())
|
||||
mangleNumber(Value.getSExtValue());
|
||||
else
|
||||
mangleNumber(Value.getZExtValue());
|
||||
mangleNumber(Value);
|
||||
}
|
||||
|
||||
void MicrosoftCXXNameMangler::mangleExpression(
|
||||
|
@ -1433,6 +1475,7 @@ void MicrosoftCXXNameMangler::mangleTemplateArg(const TemplateDecl *TD,
|
|||
// ::= <member-function-pointer>
|
||||
// ::= $E? <name> <type-encoding>
|
||||
// ::= $1? <name> <type-encoding>
|
||||
// ::= $2 <type> <value> # class NTTP
|
||||
// ::= $0A@
|
||||
// ::= <template-args>
|
||||
|
||||
|
@ -1462,6 +1505,11 @@ void MicrosoftCXXNameMangler::mangleTemplateArg(const TemplateDecl *TD,
|
|||
mangleName(FD);
|
||||
mangleFunctionEncoding(FD, /*ShouldMangle=*/true);
|
||||
}
|
||||
} else if (TA.getParamTypeForDecl()->isRecordType()) {
|
||||
Out << "$";
|
||||
auto *TPO = cast<TemplateParamObjectDecl>(ND);
|
||||
mangleTemplateArgValue(TPO->getType().getUnqualifiedType(),
|
||||
TPO->getValue());
|
||||
} else {
|
||||
mangle(ND, TA.getParamTypeForDecl()->isReferenceType() ? "$E?" : "$1?");
|
||||
}
|
||||
|
@ -1544,6 +1592,168 @@ void MicrosoftCXXNameMangler::mangleTemplateArg(const TemplateDecl *TD,
|
|||
}
|
||||
}
|
||||
|
||||
void MicrosoftCXXNameMangler::mangleTemplateArgValue(QualType T,
|
||||
const APValue &V,
|
||||
bool WithScalarType) {
|
||||
switch (V.getKind()) {
|
||||
case APValue::None:
|
||||
case APValue::Indeterminate:
|
||||
// FIXME: MSVC doesn't allow this, so we can't be sure how it should be
|
||||
// mangled.
|
||||
if (WithScalarType)
|
||||
mangleType(T, SourceRange(), QMM_Escape);
|
||||
Out << '@';
|
||||
return;
|
||||
|
||||
case APValue::Int:
|
||||
if (WithScalarType)
|
||||
mangleType(T, SourceRange(), QMM_Escape);
|
||||
Out << '0';
|
||||
mangleNumber(V.getInt());
|
||||
return;
|
||||
|
||||
case APValue::Float:
|
||||
if (WithScalarType)
|
||||
mangleType(T, SourceRange(), QMM_Escape);
|
||||
mangleFloat(V.getFloat());
|
||||
return;
|
||||
|
||||
case APValue::LValue: {
|
||||
if (WithScalarType)
|
||||
mangleType(T, SourceRange(), QMM_Escape);
|
||||
|
||||
APValue::LValueBase Base = V.getLValueBase();
|
||||
if (Base.isNull())
|
||||
Out << "0A@";
|
||||
else if (auto *VD = Base.dyn_cast<const ValueDecl*>())
|
||||
mangle(VD, T->isReferenceType() ? "E?" : "1?");
|
||||
else
|
||||
break;
|
||||
|
||||
// FIXME: MSVC doesn't support template arguments referring to subobjects
|
||||
// yet (it either mangles such template arguments as null pointers or
|
||||
// small integers or crashes). It's probably the intent to mangle the
|
||||
// declaration followed by an offset, but that's not what actually happens.
|
||||
// For now just bail.
|
||||
if (!V.hasLValuePath() || !V.getLValuePath().empty() ||
|
||||
V.isLValueOnePastTheEnd())
|
||||
break;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
case APValue::MemberPointer: {
|
||||
if (WithScalarType)
|
||||
mangleType(T, SourceRange(), QMM_Escape);
|
||||
|
||||
// FIXME: The below manglings don't include a conversion, so bail if there
|
||||
// would be one. MSVC mangles the (possibly converted) value of the
|
||||
// pointer-to-member object as if it were a struct, leading to collisions
|
||||
// in some cases.
|
||||
if (!V.getMemberPointerPath().empty())
|
||||
break;
|
||||
|
||||
const CXXRecordDecl *RD =
|
||||
T->castAs<MemberPointerType>()->getMostRecentCXXRecordDecl();
|
||||
const ValueDecl *D = V.getMemberPointerDecl();
|
||||
if (T->isMemberDataPointerType())
|
||||
mangleMemberDataPointer(RD, D, "");
|
||||
else
|
||||
mangleMemberFunctionPointer(RD, cast_or_null<CXXMethodDecl>(D), "");
|
||||
return;
|
||||
}
|
||||
|
||||
case APValue::Struct: {
|
||||
Out << '2';
|
||||
mangleType(T, SourceRange(), QMM_Escape);
|
||||
const CXXRecordDecl *RD = T->getAsCXXRecordDecl();
|
||||
assert(RD && "unexpected type for record value");
|
||||
|
||||
unsigned BaseIndex = 0;
|
||||
for (const CXXBaseSpecifier &B : RD->bases())
|
||||
mangleTemplateArgValue(B.getType(), V.getStructBase(BaseIndex++));
|
||||
for (const FieldDecl *FD : RD->fields())
|
||||
if (!FD->isUnnamedBitfield())
|
||||
mangleTemplateArgValue(FD->getType(),
|
||||
V.getStructField(FD->getFieldIndex()));
|
||||
Out << '@';
|
||||
return;
|
||||
}
|
||||
|
||||
case APValue::Union:
|
||||
Out << '2';
|
||||
mangleType(T, SourceRange(), QMM_Escape);
|
||||
// FIXME: MSVC doesn't mangle the active member, only the type, leading to
|
||||
// collisions if more than one member has the same type.
|
||||
// FIXME: MSVC doesn't yet support unions with no active member, but
|
||||
// there's an obvious mangling for that, so we use it.
|
||||
if (const FieldDecl *FD = V.getUnionField())
|
||||
mangleTemplateArgValue(FD->getType(), V.getUnionValue());
|
||||
Out << '@';
|
||||
return;
|
||||
|
||||
case APValue::ComplexInt:
|
||||
// We mangle complex types as structs, so mangle the value as a struct too.
|
||||
Out << '2';
|
||||
mangleType(T, SourceRange(), QMM_Escape);
|
||||
Out << '0';
|
||||
mangleNumber(V.getComplexIntReal());
|
||||
Out << '0';
|
||||
mangleNumber(V.getComplexIntImag());
|
||||
Out << '@';
|
||||
return;
|
||||
|
||||
case APValue::ComplexFloat:
|
||||
Out << '2';
|
||||
mangleType(T, SourceRange(), QMM_Escape);
|
||||
mangleFloat(V.getComplexFloatReal());
|
||||
mangleFloat(V.getComplexFloatImag());
|
||||
Out << '@';
|
||||
return;
|
||||
|
||||
case APValue::Array: {
|
||||
Out << '3';
|
||||
QualType ElemT = getASTContext().getAsArrayType(T)->getElementType();
|
||||
mangleType(ElemT, SourceRange(), QMM_Escape);
|
||||
for (unsigned I = 0, N = V.getArraySize(); I != N; ++I) {
|
||||
const APValue &ElemV = I < V.getArrayInitializedElts()
|
||||
? V.getArrayInitializedElt(I)
|
||||
: V.getArrayFiller();
|
||||
mangleTemplateArgValue(ElemT, ElemV, /*WithType*/false);
|
||||
Out << '@';
|
||||
}
|
||||
Out << '@';
|
||||
return;
|
||||
}
|
||||
|
||||
case APValue::Vector: {
|
||||
// __m128 is mangled as a struct containing an array. We follow this
|
||||
// approach for all vector types.
|
||||
Out << '2';
|
||||
mangleType(T, SourceRange(), QMM_Escape);
|
||||
Out << '3';
|
||||
QualType ElemT = T->castAs<VectorType>()->getElementType();
|
||||
mangleType(ElemT, SourceRange(), QMM_Escape);
|
||||
for (unsigned I = 0, N = V.getVectorLength(); I != N; ++I) {
|
||||
const APValue &ElemV = V.getVectorElt(I);
|
||||
mangleTemplateArgValue(ElemT, ElemV, /*WithType*/false);
|
||||
Out << '@';
|
||||
}
|
||||
Out << "@@";
|
||||
return;
|
||||
}
|
||||
|
||||
case APValue::AddrLabelDiff:
|
||||
case APValue::FixedPoint:
|
||||
break;
|
||||
}
|
||||
|
||||
DiagnosticsEngine &Diags = Context.getDiags();
|
||||
unsigned DiagID = Diags.getCustomDiagID(
|
||||
DiagnosticsEngine::Error, "cannot mangle this template argument yet");
|
||||
Diags.Report(DiagID);
|
||||
}
|
||||
|
||||
void MicrosoftCXXNameMangler::mangleObjCProtocol(const ObjCProtocolDecl *PD) {
|
||||
llvm::SmallString<64> TemplateMangling;
|
||||
llvm::raw_svector_ostream Stream(TemplateMangling);
|
||||
|
|
|
@ -251,28 +251,6 @@ llvm::Constant *CGCXXABI::getMemberPointerAdjustment(const CastExpr *E) {
|
|||
E->path_end());
|
||||
}
|
||||
|
||||
CharUnits CGCXXABI::getMemberPointerPathAdjustment(const APValue &MP) {
|
||||
// TODO: Store base specifiers in APValue member pointer paths so we can
|
||||
// easily reuse CGM.GetNonVirtualBaseClassOffset().
|
||||
const ValueDecl *MPD = MP.getMemberPointerDecl();
|
||||
CharUnits ThisAdjustment = CharUnits::Zero();
|
||||
ArrayRef<const CXXRecordDecl*> Path = MP.getMemberPointerPath();
|
||||
bool DerivedMember = MP.isMemberPointerToDerivedMember();
|
||||
const CXXRecordDecl *RD = cast<CXXRecordDecl>(MPD->getDeclContext());
|
||||
for (unsigned I = 0, N = Path.size(); I != N; ++I) {
|
||||
const CXXRecordDecl *Base = RD;
|
||||
const CXXRecordDecl *Derived = Path[I];
|
||||
if (DerivedMember)
|
||||
std::swap(Base, Derived);
|
||||
ThisAdjustment +=
|
||||
getContext().getASTRecordLayout(Derived).getBaseClassOffset(Base);
|
||||
RD = Path[I];
|
||||
}
|
||||
if (DerivedMember)
|
||||
ThisAdjustment = -ThisAdjustment;
|
||||
return ThisAdjustment;
|
||||
}
|
||||
|
||||
llvm::BasicBlock *
|
||||
CGCXXABI::EmitCtorCompleteObjectHandler(CodeGenFunction &CGF,
|
||||
const CXXRecordDecl *RD) {
|
||||
|
|
|
@ -220,12 +220,6 @@ protected:
|
|||
/// is required.
|
||||
llvm::Constant *getMemberPointerAdjustment(const CastExpr *E);
|
||||
|
||||
/// Computes the non-virtual adjustment needed for a member pointer
|
||||
/// conversion along an inheritance path stored in an APValue. Unlike
|
||||
/// getMemberPointerAdjustment(), the adjustment can be negative if the path
|
||||
/// is from a derived type to a base type.
|
||||
CharUnits getMemberPointerPathAdjustment(const APValue &MP);
|
||||
|
||||
public:
|
||||
virtual void emitVirtualObjectDelete(CodeGenFunction &CGF,
|
||||
const CXXDeleteExpr *DE,
|
||||
|
|
|
@ -2636,8 +2636,29 @@ ConstantAddress CodeGenModule::GetAddrOfMSGuidDecl(const MSGuidDecl *GD) {
|
|||
|
||||
ConstantAddress CodeGenModule::GetAddrOfTemplateParamObject(
|
||||
const TemplateParamObjectDecl *TPO) {
|
||||
ErrorUnsupported(TPO, "template parameter object");
|
||||
return ConstantAddress::invalid();
|
||||
StringRef Name = getMangledName(TPO);
|
||||
CharUnits Alignment = getNaturalTypeAlignment(TPO->getType());
|
||||
|
||||
if (llvm::GlobalVariable *GV = getModule().getNamedGlobal(Name))
|
||||
return ConstantAddress(GV, Alignment);
|
||||
|
||||
ConstantEmitter Emitter(*this);
|
||||
llvm::Constant *Init = Emitter.emitForInitializer(
|
||||
TPO->getValue(), TPO->getType().getAddressSpace(), TPO->getType());
|
||||
|
||||
if (!Init) {
|
||||
ErrorUnsupported(TPO, "template parameter object");
|
||||
return ConstantAddress::invalid();
|
||||
}
|
||||
|
||||
auto *GV = new llvm::GlobalVariable(
|
||||
getModule(), Init->getType(),
|
||||
/*isConstant=*/true, llvm::GlobalValue::LinkOnceODRLinkage, Init, Name);
|
||||
if (supportsCOMDAT())
|
||||
GV->setComdat(TheModule.getOrInsertComdat(GV->getName()));
|
||||
Emitter.finalize(GV);
|
||||
|
||||
return ConstantAddress(GV, Alignment);
|
||||
}
|
||||
|
||||
ConstantAddress CodeGenModule::GetWeakRefReference(const ValueDecl *VD) {
|
||||
|
|
|
@ -1088,7 +1088,7 @@ llvm::Constant *ItaniumCXXABI::EmitMemberPointer(const APValue &MP,
|
|||
if (!MPD)
|
||||
return EmitNullMemberPointer(MPT);
|
||||
|
||||
CharUnits ThisAdjustment = getMemberPointerPathAdjustment(MP);
|
||||
CharUnits ThisAdjustment = getContext().getMemberPointerPathAdjustment(MP);
|
||||
|
||||
if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(MPD))
|
||||
return BuildMemberPointer(MD, ThisAdjustment);
|
||||
|
|
|
@ -0,0 +1,343 @@
|
|||
// RUN: %clang_cc1 -std=c++20 %s -triple x86_64-linux-gnu -emit-llvm -o - | FileCheck %s
|
||||
// RUN: %clang_cc1 -std=c++20 %s -triple x86_64-windows -emit-llvm -o - | FileCheck %s --check-prefix=MSABI
|
||||
|
||||
#define fold(x) (__builtin_constant_p(x) ? (x) : (x))
|
||||
|
||||
struct A { int a; const int b; };
|
||||
template<A> void f() {}
|
||||
|
||||
// CHECK: define weak_odr void @_Z1fIXtl1ALi1ELi2EEEEvv(
|
||||
// MSABI: define {{.*}} @"??$f@$2UA@@H00$$CBH01@@@YAXXZ"
|
||||
template void f<A{1, 2}>();
|
||||
|
||||
struct B { const int *p; int k; };
|
||||
template<B> void f() {}
|
||||
|
||||
int n = 0;
|
||||
// CHECK: define weak_odr void @_Z1fIXtl1BadL_Z1nEEEEvv(
|
||||
// MSABI: define {{.*}} @"??$f@$2UB@@PEBH1?n@@3HAH0A@@@@YAXXZ"
|
||||
template void f<B{&n}>();
|
||||
// CHECK: define weak_odr void @_Z1fIXtl1BLPKi0ELi1EEEEvv(
|
||||
// MSABI: define {{.*}} @"??$f@$2UB@@PEBH0A@H00@@@YAXXZ"
|
||||
template void f<B{nullptr, 1}>();
|
||||
// CHECK: define weak_odr void @_Z1fIXtl1BEEEvv(
|
||||
// MSABI: define {{.*}} @"??$f@$2UB@@PEBH0A@H0A@@@@YAXXZ"
|
||||
template void f<B{nullptr}>();
|
||||
#ifndef _WIN32
|
||||
// FIXME: MSVC crashes on the first of these and mangles the second the same as
|
||||
// the nullptr version. Check the output is correct once we have a reference to
|
||||
// compare against.
|
||||
// CHECK: define weak_odr void @_Z1fIXtl1BLPKi32EEEEvv(
|
||||
template void f<B{fold((int*)32)}>();
|
||||
// CHECK: define weak_odr void @_Z1fIXtl1BrcPKiLi0EEEEvv(
|
||||
template void f<B{fold(reinterpret_cast<int*>(0))}>();
|
||||
#endif
|
||||
|
||||
// Pointers to subobjects.
|
||||
struct Nested { union { int k; int arr[2]; }; } nested[2];
|
||||
struct Derived : A, Nested { int z; } extern derived;
|
||||
#ifndef _WIN32
|
||||
// CHECK: define weak_odr void @_Z1fIXtl1BadsoKiL_Z6nestedE_EEEEvv
|
||||
// FIXME: MSVC generates the garbage mangling ??$f@$2UB@@PEAH0A@H0A@@@@YAXXZ
|
||||
// for this.
|
||||
template void f<B{&nested[0].k}>();
|
||||
// FIXME: MSVC crashes on these.
|
||||
// CHECK: define weak_odr void @_Z1fIXtl1BadsoKiL_Z6nestedE16_0pEEEEvv
|
||||
template void f<B{&nested[1].arr[2]}>();
|
||||
// CHECK: define weak_odr void @_Z1fIXtl1BadsoKiL_Z7derivedE8pEEEEvv
|
||||
template void f<B{&derived.b + 1}>();
|
||||
// CHECK: define weak_odr void @_Z1fIXtl1BcvPKiplcvPcadL_Z7derivedELl16EEEEvv
|
||||
template void f<B{fold(&derived.b + 3)}>();
|
||||
#endif
|
||||
|
||||
// References to subobjects.
|
||||
struct BR { const int &r; };
|
||||
template<BR> void f() {}
|
||||
#ifndef _WIN32
|
||||
// FIXME: MSVC produces garbage manglings for these.
|
||||
// CHECK: define weak_odr void @_Z1fIXtl2BRsoKiL_Z6nestedE_EEEEvv
|
||||
template void f<BR{nested[0].k}>();
|
||||
// CHECK: define weak_odr void @_Z1fIXtl2BRsoKiL_Z6nestedE12_0EEEEvv
|
||||
template void f<BR{nested[1].arr[1]}>();
|
||||
// CHECK: define weak_odr void @_Z1fIXtl2BRsoKiL_Z7derivedE4EEEEvv
|
||||
template void f<BR{derived.b}>();
|
||||
// FIXME: Crashes MSVC.
|
||||
// CHECK: define weak_odr void @_Z1fIXtl2BRdecvPKiplcvPcadL_Z7derivedELl16EEEEvv
|
||||
template void f<BR{fold(*(&derived.b + 3))}>();
|
||||
#endif
|
||||
|
||||
// Qualification conversions.
|
||||
struct C { const int *p; };
|
||||
template<C> void f() {}
|
||||
#ifndef _WIN32
|
||||
// FIXME: MSVC produces a garbage mangling for this.
|
||||
// CHECK: define weak_odr void @_Z1fIXtl1CadsoKiL_Z7derivedE4EEEEvv
|
||||
template void f<C{&derived.b}>();
|
||||
#endif
|
||||
|
||||
// Pointers to members.
|
||||
struct D { const int Derived::*p; int k; };
|
||||
template<D> void f() {}
|
||||
// CHECK: define weak_odr void @_Z1fIXtl1DLM7DerivedKi0ELi1EEEEvv
|
||||
// MSABI: define {{.*}} @"??$f@$2UD@@PERDerived@@H0?0H00@@@YAXXZ"
|
||||
template void f<D{nullptr, 1}>();
|
||||
// CHECK: define weak_odr void @_Z1fIXtl1DEEEvv
|
||||
// MSABI: define {{.*}} @"??$f@$2UD@@PERDerived@@H0?0H0A@@@@YAXXZ"
|
||||
template void f<D{nullptr}>();
|
||||
// CHECK: define weak_odr void @_Z1fIXtl1DadL_ZN7Derived1zEEEEEvv
|
||||
// MSABI: define {{.*}} @"??$f@$2UD@@PERDerived@@H0BA@H0A@@@@YAXXZ"
|
||||
template void f<D{&Derived::z}>();
|
||||
#ifndef _WIN32
|
||||
// CHECK: define weak_odr void @_Z1fIXtl1DmcM7DerivedKiadL_ZN1A1aEEEEEEvv
|
||||
// MSABI-FIXME: define {{.*}} @"??$f@$2UD@@PERDerived@@H0A@H0A@@@@YAXXZ"
|
||||
template void f<D{&A::a}>();
|
||||
// CHECK: define weak_odr void @_Z1fIXtl1DmcM7DerivedKiadL_ZN1A1bEEEEEEvv
|
||||
// MSABI-FIXME: define {{.*}} @"??$f@$2UD@@PERDerived@@H03H0A@@@@YAXXZ"
|
||||
template void f<D{&A::b}>();
|
||||
// FIXME: Is the Ut_1 mangling here correct?
|
||||
// CHECK: define weak_odr void @_Z1fIXtl1DmcM7DerivedKiadL_ZN6NestedUt_1kEE8ELi2EEEEvv
|
||||
// FIXME: This mangles the same as &A::a (bug in the MS ABI).
|
||||
// MSABI-FIXME: define {{.*}} @"??$f@$2UD@@PERDerived@@H0A@H01@@@YAXXZ"
|
||||
template void f<D{&Nested::k, 2}>();
|
||||
struct MoreDerived : A, Derived { int z; };
|
||||
// CHECK: define weak_odr void @_Z1fIXtl1DmcM7DerivedKiadL_ZN11MoreDerived1zEEn8EEEEvv
|
||||
// MSABI-FIXME: define {{.*}} @"??$f@$2UD@@PERDerived@@H0BI@H0A@@@@YAXXZ"
|
||||
template void f<D{(int Derived::*)&MoreDerived::z}>();
|
||||
#endif
|
||||
|
||||
// FIXME: Pointers to member functions.
|
||||
|
||||
union E {
|
||||
int n;
|
||||
float f;
|
||||
constexpr E() {}
|
||||
constexpr E(int n) : n(n) {}
|
||||
constexpr E(float f) : f(f) {}
|
||||
};
|
||||
template<E> void f() {}
|
||||
|
||||
// Union members.
|
||||
// CHECK: define weak_odr void @_Z1fIXL1EEEEvv(
|
||||
// FIXME: MSVC rejects this; check this is the mangling MSVC uses when they
|
||||
// start accepting.
|
||||
// MSABI: define {{.*}} @"??$f@$2TE@@@@@YAXXZ"
|
||||
template void f<E{}>();
|
||||
// CHECK: define weak_odr void @_Z1fIXtl1EEEEvv(
|
||||
// MSABI: define {{.*}} @"??$f@$2TE@@H0A@@@@YAXXZ"
|
||||
template void f<E(0)>();
|
||||
// CHECK: define weak_odr void @_Z1fIXtl1Edi1nLi42EEEEvv(
|
||||
// MSABI: define {{.*}} @"??$f@$2TE@@H0CK@@@@YAXXZ"
|
||||
template void f<E(42)>();
|
||||
// CHECK: define weak_odr void @_Z1fIXtl1Edi1fLf00000000EEEEvv(
|
||||
// MSABI: define {{.*}} @"??$f@$2TE@@MAA@@@@YAXXZ"
|
||||
template void f<E(0.f)>();
|
||||
|
||||
// immintrin.h vector types.
|
||||
typedef float __m128 __attribute__((__vector_size__(16)));
|
||||
typedef double __m128d __attribute__((__vector_size__(16)));
|
||||
typedef long long __m128i __attribute__((__vector_size__(16)));
|
||||
struct M128 { __m128 a; };
|
||||
struct M128D { __m128d b; };
|
||||
struct M128I { __m128i c; };
|
||||
template<M128> void f() {}
|
||||
template<M128D> void f() {}
|
||||
template<M128I> void f() {}
|
||||
// MSABI: define {{.*}} @"??$f@$2UM128@@2T__m128@@3MADPIAAAAA@@AEAAAAAAA@@AEAEAAAAA@@AEAIAAAAA@@@@@@@YAXXZ"
|
||||
template void f<M128{1, 2, 3, 4}>();
|
||||
// MSABI: define {{.*}} @"??$f@$2UM128D@@2U__m128d@@3NBDPPAAAAAAAAAAAAA@@BEAAAAAAAAAAAAAAA@@@@@@@YAXXZ"
|
||||
template void f<M128D{1, 2}>();
|
||||
// FIXME: We define __m128i as a vector of long long, whereas MSVC appears to
|
||||
// mangle it as if it were a vector of char.
|
||||
// MSABI-FIXME: define {{.*}} @"??$f@$2UM128I@@2T__m128i@@3D00@01@0A@@0A@@0A@@0A@@0A@@0A@@0A@@0A@@0A@@0A@@0A@@0A@@0A@@0A@@@@@@@YAXXZ"
|
||||
// MSABI: define {{.*}} @"??$f@$2UM128I@@2T__m128i@@3_J00@01@@@@@@YAXXZ"
|
||||
template void f<M128I{1, 2}>();
|
||||
|
||||
// Extensions, and dropping trailing zero-initialized elements of 'tl'
|
||||
// manglings.
|
||||
typedef int __attribute__((ext_vector_type(3))) VI3;
|
||||
struct F { VI3 v; _Complex int ci; _Complex float cf; };
|
||||
template<F> void f() {}
|
||||
// CHECK: define weak_odr void @_Z1fIXtl1FtlDv3_iLi1ELi2ELi3EEtlCiLi4ELi5EEtlCfLf40c00000ELf40e00000EEEEEvv
|
||||
// MSABI: define {{.*}} @"??$f@$2UF@@2T?$__vector@H$02@__clang@@3H00@01@02@@@2U?$_Complex@H@3@0304@2U?$_Complex@M@3@AEAMAAAAA@AEAOAAAAA@@@@@YAXXZ"
|
||||
template void f<F{{1, 2, 3}, {4, 5}, {6, 7}}>();
|
||||
// CHECK: define weak_odr void @_Z1fIXtl1FtlDv3_iLi1ELi2ELi3EEtlCiLi4ELi5EEtlCfLf40c00000EEEEEvv
|
||||
template void f<F{{1, 2, 3}, {4, 5}, {6, 0}}>();
|
||||
// CHECK: define weak_odr void @_Z1fIXtl1FtlDv3_iLi1ELi2ELi3EEtlCiLi4ELi5EEEEEvv
|
||||
template void f<F{{1, 2, 3}, {4, 5}, {0, 0}}>();
|
||||
// CHECK: define weak_odr void @_Z1fIXtl1FtlDv3_iLi1ELi2ELi3EEtlCiLi4EEEEEvv
|
||||
template void f<F{{1, 2, 3}, {4, 0}, {0, 0}}>();
|
||||
// CHECK: define weak_odr void @_Z1fIXtl1FtlDv3_iLi1ELi2ELi3EEEEEvv
|
||||
template void f<F{{1, 2, 3}, {0, 0}, {0, 0}}>();
|
||||
// CHECK: define weak_odr void @_Z1fIXtl1FtlDv3_iLi1ELi2EEEEEvv
|
||||
template void f<F{{1, 2, 0}, {0, 0}, {0, 0}}>();
|
||||
// CHECK: define weak_odr void @_Z1fIXtl1FtlDv3_iLi1EEEEEvv
|
||||
template void f<F{{1, 0, 0}, {0, 0}, {0, 0}}>();
|
||||
// CHECK: define weak_odr void @_Z1fIXtl1FEEEvv
|
||||
// MSABI: define {{.*}} @"??$f@$2UF@@2T?$__vector@H$02@__clang@@3H0A@@0A@@0A@@@@2U?$_Complex@H@3@0A@0A@@2U?$_Complex@M@3@AA@AA@@@@@YAXXZ"
|
||||
template void f<F{{0, 0, 0}, {0, 0}, {0, 0}}>();
|
||||
|
||||
// Unnamed bit-fields.
|
||||
struct G {
|
||||
int : 3;
|
||||
int a : 4;
|
||||
int : 5;
|
||||
int b : 6;
|
||||
int : 7;
|
||||
};
|
||||
template<G> void f() {}
|
||||
// CHECK: define weak_odr void @_Z1fIXtl1GEEEvv
|
||||
// MSABI: define {{.*}} @"??$f@$2UG@@H0A@H0A@@@@YAXXZ"
|
||||
template void f<(G())>();
|
||||
// CHECK: define weak_odr void @_Z1fIXtl1GLi1EEEEvv
|
||||
// MSABI: define {{.*}} @"??$f@$2UG@@H00H0A@@@@YAXXZ"
|
||||
template void f<G{1}>();
|
||||
// CHECK: define weak_odr void @_Z1fIXtl1GLi1ELi2EEEEvv
|
||||
// MSABI: define {{.*}} @"??$f@$2UG@@H00H01@@@YAXXZ"
|
||||
template void f<G{1, 2}>();
|
||||
// CHECK: define weak_odr void @_Z1fIXtl1GLin8ELin32EEEEvv
|
||||
// MSABI: define {{.*}} @"??$f@$2UG@@H0?7H0?CA@@@@YAXXZ"
|
||||
template void f<G{-8, -32}>();
|
||||
|
||||
// Empty and nearly-empty unions.
|
||||
// Some of the MSVC manglings here are our invention, because MSVC rejects, but
|
||||
// seem likely to be right.
|
||||
union H1 {};
|
||||
union H2 { int : 1, : 2, : 3; };
|
||||
union H3 { int : 1, a, : 2, b, : 3; };
|
||||
struct H4 { H2 h2; };
|
||||
template<H1> void f() {}
|
||||
template<H2> void f() {}
|
||||
template<H3> void f() {}
|
||||
template<H4> void f() {}
|
||||
// CHECK: define weak_odr void @_Z1fIXL2H1EEEvv
|
||||
// MSABI: define {{.*}} @"??$f@$2TH1@@@@@YAXXZ"
|
||||
template void f<H1{}>();
|
||||
// CHECK: define weak_odr void @_Z1fIXL2H2EEEvv
|
||||
// MSABI: define {{.*}} @"??$f@$2TH2@@@@@YAXXZ"
|
||||
template void f<H2{}>();
|
||||
// CHECK: define weak_odr void @_Z1fIXtl2H3EEEvv
|
||||
// MSABI: define {{.*}} @"??$f@$2TH3@@H0A@@@@YAXXZ"
|
||||
template void f<H3{.a = 0}>();
|
||||
// CHECK: define weak_odr void @_Z1fIXtl2H3di1aLi1EEEEvv
|
||||
// MSABI: define {{.*}} @"??$f@$2TH3@@H00@@@YAXXZ"
|
||||
template void f<H3{.a = 1}>();
|
||||
// FIXME: Leads to mangling collision under MS ABI; same mangling as the {.a = 0} case.
|
||||
#ifndef _WIN32
|
||||
// CHECK: define weak_odr void @_Z1fIXtl2H3di1bLi0EEEEvv
|
||||
template void f<H3{.b = 0}>();
|
||||
#endif
|
||||
// CHECK: define weak_odr void @_Z1fIXtl2H4EEEvv
|
||||
// MSABI: define {{.*}} @"??$f@$2UH4@@2TH2@@@@@@YAXXZ"
|
||||
template void f<H4{}>();
|
||||
|
||||
// Floating-point.
|
||||
struct I {
|
||||
float f;
|
||||
double d;
|
||||
long double ld;
|
||||
};
|
||||
template<I> void f() {}
|
||||
// CHECK: define weak_odr void @_Z1fIXtl1IEEEvv
|
||||
// MSABI: define {{.*}} @"??$f@$2UI@@MAA@NBA@OBA@@@@YAXXZ"
|
||||
template void f<I{0.0, 0.0, 0.0}>();
|
||||
// CHECK: define weak_odr void @_Z1fIXtl1ILf80000000ELd8000000000000000ELe80000000000000000000EEEEvv
|
||||
// MSABI: define {{.*}} @"??$f@$2UI@@MAIAAAAAAA@NBIAAAAAAAAAAAAAAA@OBIAAAAAAAAAAAAAAA@@@@YAXXZ"
|
||||
template void f<I{-0.0, -0.0, -0.0}>();
|
||||
// CHECK: define weak_odr void @_Z1fIXtl1ILf3f800000ELd4000000000000000ELec000c000000000000000EEEEvv
|
||||
// MSABI: define {{.*}} @"??$f@$2UI@@MADPIAAAAA@NBEAAAAAAAAAAAAAAA@OBMAAIAAAAAAAAAAAA@@@@YAXXZ"
|
||||
template void f<I{1.0, 2.0, -3.0}>();
|
||||
// CHECK: define {{.*}} @_Z1fIXtl1ILf00000000ELd0000000000000000ELe3bcd8000000000000000EEEEvv
|
||||
// Note that "small integer" special-case manglings 'A@', '0', '1', ... are
|
||||
// used here and represent tiny denormal values!
|
||||
// MSABI: define {{.*}} @"??$f@$2UI@@MAA@NBA@OB0@@@YAXXZ"
|
||||
template void f<I{0.0, 0.2e-323, 0.5e-323}>();
|
||||
// CHECK: define {{.*}} @_Z1fIXtl1ILf00000000ELd0000000000000002ELebbce8000000000000000EEEEvv
|
||||
// ... but the special-case '?' mangling for bit 63 being set is not used.
|
||||
// MSABI: define {{.*}} @"??$f@$2UI@@MAA@NB1OBIAAAAAAAAAAAAAAC@@@@YAXXZ"
|
||||
template void f<I{0.0, 1.0e-323, -1.0e-323}>();
|
||||
|
||||
// Base classes and members of class type.
|
||||
struct J1 { int a, b; };
|
||||
struct JEmpty {};
|
||||
struct J2 { int c, d; };
|
||||
struct J : J1, JEmpty, J2 { int e; };
|
||||
template<J> void f() {}
|
||||
// CHECK: define weak_odr void @_Z1fIXtl1JEEEvv
|
||||
// MSABI: define {{.*}} @"??$f@$2UJ@@2UJ1@@H0A@H0A@@2UJEmpty@@@2UJ2@@H0A@H0A@@H0A@@@@YAXXZ"
|
||||
template void f<J{}>();
|
||||
// CHECK: define weak_odr void @_Z1fIXtl1Jtl2J1Li1ELi2EEtl6JEmptyEtl2J2Li3ELi4EELi5EEEEvv
|
||||
// MSABI: define {{.*}} @"??$f@$2UJ@@2UJ1@@H00H01@2UJEmpty@@@2UJ2@@H02H03@H04@@@YAXXZ"
|
||||
template void f<J{{1, 2}, {}, {3, 4}, 5}>();
|
||||
|
||||
struct J3 { J1 j1; };
|
||||
template<J3> void f() {}
|
||||
// CHECK: define {{.*}} @_Z1fIXtl2J3tl2J1Li1ELi2EEEEEvv
|
||||
// MSABI: define {{.*}} @"??$f@$2UJ3@@2UJ1@@H00H01@@@@YAXXZ"
|
||||
template void f<J3{1, 2}>();
|
||||
|
||||
// Arrays.
|
||||
struct K { int n[2][3]; };
|
||||
template<K> void f() {}
|
||||
// CHECK: define {{.*}} @_Z1fIXtl1KtlA2_A3_itlS1_Li1ELi2EEEEEEvv
|
||||
// MSABI: define {{.*}} @"??$f@$2UK@@3$$BY02H3H00@01@0A@@@@3H0A@@0A@@0A@@@@@@@@YAXXZ"
|
||||
template void f<K{1, 2}>();
|
||||
// CHECK: define {{.*}} @_Z1fIXtl1KtlA2_A3_itlS1_Li1ELi2ELi3EEtlS1_Li4ELi5ELi6EEEEEEvv
|
||||
// MSABI: define {{.*}} @"??$f@$2UK@@3$$BY02H3H00@01@02@@@3H03@04@05@@@@@@@YAXXZ"
|
||||
template void f<K{1, 2, 3, 4, 5, 6}>();
|
||||
|
||||
struct K1 { int a, b; };
|
||||
struct K2 : K1 { int c; };
|
||||
struct K3 { K2 k2[2]; };
|
||||
template<K3> void f() {}
|
||||
// CHECK: define {{.*}} @_Z1fIXtl2K3tlA2_2K2tlS1_tl2K1Li1EEEEEEEvv
|
||||
// MSABI: define {{.*}} @"??$f@$2UK3@@3UK2@@2U2@2UK1@@H00H0A@@H0A@@@2U2@2U3@H0A@H0A@@H0A@@@@@@@YAXXZ"
|
||||
template void f<K3{1}>();
|
||||
template void f<K3{1, 2, 3, 4, 5, 6}>();
|
||||
|
||||
namespace CvQualifiers {
|
||||
struct A { const int a; int *const b; int c; };
|
||||
template<A> void f() {}
|
||||
// CHECK: define {{.*}} @_ZN12CvQualifiers1fIXtlNS_1AELi0ELPi0ELi1EEEEEvv
|
||||
// MSABI: define {{.*}} @"??$f@$2UA@CvQualifiers@@$$CBH0A@QEAH0A@H00@@CvQualifiers@@YAXXZ"
|
||||
template void f<A{.c = 1}>();
|
||||
|
||||
using T1 = const int;
|
||||
using T2 = T1[5];
|
||||
using T3 = const T2;
|
||||
struct B { T3 arr; };
|
||||
template<B> void f() {}
|
||||
// CHECK: define {{.*}} @_ZN12CvQualifiers1fIXtlNS_1BEtlA5_iLi1ELi2ELi3ELi4ELi5EEEEEEvv
|
||||
// MSABI: define {{.*}} @"??$f@$2UB@CvQualifiers@@3$$CBH00@01@02@03@04@@@@CvQualifiers@@YAXXZ"
|
||||
template void f<B{1, 2, 3, 4, 5}>();
|
||||
}
|
||||
|
||||
struct L {
|
||||
signed char a = -1;
|
||||
unsigned char b = -1;
|
||||
short c = -1;
|
||||
unsigned short d = -1;
|
||||
int e = -1;
|
||||
unsigned int f = -1;
|
||||
long g = -1;
|
||||
unsigned long h = -1;
|
||||
long long i = -1;
|
||||
unsigned long long j = -1;
|
||||
};
|
||||
template<L> void f() {}
|
||||
// CHECK: define {{.*}} @_Z1fIXtl1LLan1ELh255ELsn1ELt65535ELin1ELj4294967295ELln1ELm18446744073709551615ELxn1ELy18446744073709551615EEEEvv
|
||||
// MSABI: define {{.*}} @"??$f@$2UL@@C0?0E0PP@F0?0G0PPPP@H0?0I0PPPPPPPP@J0?0K0PPPPPPPP@_J0?0_K0?0@@@YAXXZ"
|
||||
template void f<L{}>();
|
||||
|
||||
// Template parameter objects.
|
||||
struct M { int n; };
|
||||
template<M a> constexpr const M &f() { return a; }
|
||||
// CHECK: define {{.*}} @_Z1fIXtl1MLi42EEEERKS0_v
|
||||
// CHECK: ret {{.*}} @_ZTAXtl1MLi42EEE
|
||||
// MSABI: define {{.*}} @"??$f@$2UM@@H0CK@@@@YAAEBUM@@XZ"
|
||||
// MSABI: ret {{.*}} @"??__N2UM@@H0CK@@@"
|
||||
template const M &f<M{42}>();
|
||||
|
||||
template<const M *p> void g() {}
|
||||
// CHECK: define {{.*}} @_Z1gIXadL_ZTAXtl1MLi10EEEEEEvv
|
||||
// MSABI: define {{.*}} @"??$g@$1??__N2UM@@H09@@@@YAXXZ"
|
||||
template void g<&f<M{10}>()>();
|
|
@ -310,3 +310,20 @@ struct UUIDType4 : UUIDType3<G> {
|
|||
template struct UUIDType4<&__uuidof(uuid)>;
|
||||
// CHECK: "?bar@?$UUIDType4@$1?_GUID_12345678_1234_1234_1234_1234567890ab@@3U__s_GUID@@B@@QAEXXZ"
|
||||
// CHECK: "?foo@?$UUIDType3@$1?_GUID_12345678_1234_1234_1234_1234567890ab@@3U__s_GUID@@B@@QAEXXZ"
|
||||
|
||||
#ifdef _WIN64
|
||||
template<__int128 N> struct Int128 {};
|
||||
template<unsigned __int128 N> struct UInt128 {};
|
||||
// X64: define {{.*}} @"?fun_int128@@YAXU?$Int128@$0A@@@@Z"(
|
||||
void fun_int128(Int128<0>) {}
|
||||
// X64: define {{.*}} @"?fun_int128@@YAXU?$Int128@$0?0@@@Z"(
|
||||
void fun_int128(Int128<-1>) {}
|
||||
// X64: define {{.*}} @"?fun_int128@@YAXU?$Int128@$0DPPPPPPPPPPPPPPPAAAAAAAAAAAAAAAB@@@@Z"(
|
||||
void fun_int128(Int128<(__int128)9223372036854775807 * (__int128)9223372036854775807>) {}
|
||||
// X64: define {{.*}} @"?fun_uint128@@YAXU?$UInt128@$0A@@@@Z"(
|
||||
void fun_uint128(UInt128<0>) {}
|
||||
// X64: define {{.*}} @"?fun_uint128@@YAXU?$UInt128@$0?0@@@Z"(
|
||||
void fun_uint128(UInt128<(unsigned __int128)-1>) {}
|
||||
// X64: define {{.*}} @"?fun_uint128@@YAXU?$UInt128@$0DPPPPPPPPPPPPPPPAAAAAAAAAAAAAAAB@@@@Z"(
|
||||
void fun_uint128(UInt128<(unsigned __int128)9223372036854775807 * (unsigned __int128)9223372036854775807>) {}
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++20 %s -emit-llvm -o - | FileCheck %s --check-prefixes=ITANIUM,CHECK
|
||||
// RUN: %clang_cc1 -triple x86_64-windows -std=c++20 %s -emit-llvm -o - | FileCheck %s --check-prefixes=MSABI,CHECK
|
||||
|
||||
struct S { char buf[32]; };
|
||||
template<S s> constexpr const char *begin() { return s.buf; }
|
||||
template<S s> constexpr const char *end() { return s.buf + __builtin_strlen(s.buf); }
|
||||
|
||||
// ITANIUM: [[HELLO:@_ZTAXtl1StlA32_cLc104ELc101ELc108ELc108ELc111ELc32ELc119ELc111ELc114ELc108ELc100EEEE]]
|
||||
// MSABI: [[HELLO:@"[?][?]__N2US@@3D0GI@@0GF@@0GM@@0GM@@0GP@@0CA@@0HH@@0GP@@0HC@@0GM@@0GE@@0A@@0A@@0A@@0A@@0A@@0A@@0A@@0A@@0A@@0A@@0A@@0A@@0A@@0A@@0A@@0A@@0A@@0A@@0A@@0A@@0A@@@@@"]]
|
||||
// CHECK-SAME: = linkonce_odr constant { <{ [11 x i8], [21 x i8] }> } { <{ [11 x i8], [21 x i8] }> <{ [11 x i8] c"hello world", [21 x i8] zeroinitializer }> }, comdat
|
||||
|
||||
// ITANIUM: @p
|
||||
// MSABI: @"?p@@3PEBDEB"
|
||||
// CHECK-SAME: global i8* getelementptr inbounds ({{.*}}* [[HELLO]], i32 0, i32 0, i32 0, i32 0)
|
||||
const char *p = begin<S{"hello world"}>();
|
||||
// ITANIUM: @q
|
||||
// MSABI: @"?q@@3PEBDEB"
|
||||
// CHECK-SAME: global i8* getelementptr (i8, i8* getelementptr inbounds ({{.*}}* [[HELLO]], i32 0, i32 0, i32 0, i32 0), i64 11)
|
||||
const char *q = end<S{"hello world"}>();
|
Loading…
Reference in New Issue