forked from OSchip/llvm-project
[ms-cxxabi] Use sugared types in the mangler instead of canonical types
At this point, it's clear that the MSVC mangler uses the type-as-written instead of the canonical type, so this should bring us closer to MSVC. The main thrust of this change is to fix the way we mangle decayed array parameters of function pointer parameters. With a DecayedType sugar node, this code can now be much simpler. Fixes PR16096. This also fixes a separate issue that Richard spotted in review. Because separate declarations of the same entity can be spelled and mangled differently, MSVC always mangles the earliest declaration in an attempt to avoid link errors. Clang now does the same. Reviewers: rsmith Differential Revision: http://llvm-reviews.chandlerc.com/D844 llvm-svn: 184777
This commit is contained in:
parent
b11a192dfc
commit
18da98ef99
|
@ -125,7 +125,7 @@ private:
|
|||
void mangleFunctionType(const FunctionType *T, const FunctionDecl *D,
|
||||
bool IsStructor, bool IsInstMethod);
|
||||
void mangleDecayedArrayType(const ArrayType *T, bool IsGlobal);
|
||||
void mangleArrayType(const ArrayType *T, Qualifiers Quals);
|
||||
void mangleArrayType(const ArrayType *T);
|
||||
void mangleFunctionClass(const FunctionDecl *FD);
|
||||
void mangleCallingConvention(const FunctionType *T, bool IsInstMethod = false);
|
||||
void mangleIntegerLiteral(const llvm::APSInt &Number, bool IsBoolean);
|
||||
|
@ -257,13 +257,20 @@ void MicrosoftCXXNameMangler::mangle(const NamedDecl *D,
|
|||
void MicrosoftCXXNameMangler::mangleFunctionEncoding(const FunctionDecl *FD) {
|
||||
// <type-encoding> ::= <function-class> <function-type>
|
||||
|
||||
// Since MSVC operates on the type as written and not the canonical type, it
|
||||
// actually matters which decl we have here. MSVC appears to choose the
|
||||
// first, since it is most likely to be the declaration in a header file.
|
||||
FD = FD->getFirstDeclaration();
|
||||
|
||||
// Don't mangle in the type if this isn't a decl we should typically mangle.
|
||||
if (!Context.shouldMangleDeclName(FD))
|
||||
return;
|
||||
|
||||
// We should never ever see a FunctionNoProtoType at this point.
|
||||
// We don't even know how to mangle their types anyway :).
|
||||
const FunctionProtoType *FT = FD->getType()->castAs<FunctionProtoType>();
|
||||
TypeSourceInfo *TSI = FD->getTypeSourceInfo();
|
||||
QualType T = TSI ? TSI->getType() : FD->getType();
|
||||
const FunctionProtoType *FT = T->castAs<FunctionProtoType>();
|
||||
|
||||
bool InStructor = false, InInstMethod = false;
|
||||
const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD);
|
||||
|
@ -980,17 +987,24 @@ void MicrosoftCXXNameMangler::manglePointerQualifiers(Qualifiers Quals) {
|
|||
|
||||
void MicrosoftCXXNameMangler::mangleArgumentType(QualType T,
|
||||
SourceRange Range) {
|
||||
// MSVC will backreference two canonically equivalent types that have slightly
|
||||
// different manglings when mangled alone.
|
||||
void *TypePtr = getASTContext().getCanonicalType(T).getAsOpaquePtr();
|
||||
ArgBackRefMap::iterator Found = TypeBackReferences.find(TypePtr);
|
||||
|
||||
if (Found == TypeBackReferences.end()) {
|
||||
size_t OutSizeBefore = Out.GetNumBytesInBuffer();
|
||||
|
||||
if (const ArrayType *AT = getASTContext().getAsArrayType(T)) {
|
||||
mangleDecayedArrayType(AT, false);
|
||||
} else if (const FunctionType *FT = T->getAs<FunctionType>()) {
|
||||
Out << "P6";
|
||||
mangleFunctionType(FT, 0, false, false);
|
||||
if (const DecayedType *DT = T->getAs<DecayedType>()) {
|
||||
QualType OT = DT->getOriginalType();
|
||||
if (const ArrayType *AT = getASTContext().getAsArrayType(OT)) {
|
||||
mangleDecayedArrayType(AT, false);
|
||||
} else if (const FunctionType *FT = OT->getAs<FunctionType>()) {
|
||||
Out << "P6";
|
||||
mangleFunctionType(FT, 0, false, false);
|
||||
} else {
|
||||
llvm_unreachable("unexpected decayed type");
|
||||
}
|
||||
} else {
|
||||
mangleType(T, Range, QMM_Drop);
|
||||
}
|
||||
|
@ -1010,16 +1024,18 @@ void MicrosoftCXXNameMangler::mangleArgumentType(QualType T,
|
|||
|
||||
void MicrosoftCXXNameMangler::mangleType(QualType T, SourceRange Range,
|
||||
QualifierMangleMode QMM) {
|
||||
// Only operate on the canonical type!
|
||||
T = getASTContext().getCanonicalType(T);
|
||||
// Don't use the canonical types. MSVC includes things like 'const' on
|
||||
// pointer arguments to function pointers that canonicalization strips away.
|
||||
T = T.getDesugaredType(getASTContext());
|
||||
Qualifiers Quals = T.getLocalQualifiers();
|
||||
|
||||
if (const ArrayType *AT = dyn_cast<ArrayType>(T)) {
|
||||
if (const ArrayType *AT = getASTContext().getAsArrayType(T)) {
|
||||
// If there were any Quals, getAsArrayType() pushed them onto the array
|
||||
// element type.
|
||||
if (QMM == QMM_Mangle)
|
||||
Out << 'A';
|
||||
else if (QMM == QMM_Escape || QMM == QMM_Result)
|
||||
Out << "$$B";
|
||||
mangleArrayType(AT, Quals);
|
||||
mangleArrayType(AT);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1180,6 +1196,9 @@ void MicrosoftCXXNameMangler::mangleFunctionType(const FunctionType *T,
|
|||
// <return-type> <argument-list> <throw-spec>
|
||||
const FunctionProtoType *Proto = cast<FunctionProtoType>(T);
|
||||
|
||||
SourceRange Range;
|
||||
if (D) Range = D->getSourceRange();
|
||||
|
||||
// If this is a C++ instance method, mangle the CVR qualifiers for the
|
||||
// this pointer.
|
||||
if (IsInstMethod)
|
||||
|
@ -1201,7 +1220,7 @@ void MicrosoftCXXNameMangler::mangleFunctionType(const FunctionType *T,
|
|||
}
|
||||
Out << '@';
|
||||
} else {
|
||||
mangleType(Proto->getResultType(), SourceRange(), QMM_Result);
|
||||
mangleType(Proto->getResultType(), Range, QMM_Result);
|
||||
}
|
||||
|
||||
// <argument-list> ::= X # void
|
||||
|
@ -1210,23 +1229,11 @@ void MicrosoftCXXNameMangler::mangleFunctionType(const FunctionType *T,
|
|||
if (Proto->getNumArgs() == 0 && !Proto->isVariadic()) {
|
||||
Out << 'X';
|
||||
} else {
|
||||
if (D) {
|
||||
// If we got a decl, use the type-as-written to make sure arrays
|
||||
// get mangled right. Note that we can't rely on the TSI
|
||||
// existing if (for example) the parameter was synthesized.
|
||||
for (FunctionDecl::param_const_iterator Parm = D->param_begin(),
|
||||
ParmEnd = D->param_end(); Parm != ParmEnd; ++Parm) {
|
||||
TypeSourceInfo *TSI = (*Parm)->getTypeSourceInfo();
|
||||
QualType Type = TSI ? TSI->getType() : (*Parm)->getType();
|
||||
mangleArgumentType(Type, (*Parm)->getSourceRange());
|
||||
}
|
||||
} else {
|
||||
// Happens for function pointer type arguments for example.
|
||||
for (FunctionProtoType::arg_type_iterator Arg = Proto->arg_type_begin(),
|
||||
ArgEnd = Proto->arg_type_end();
|
||||
Arg != ArgEnd; ++Arg)
|
||||
mangleArgumentType(*Arg, SourceRange());
|
||||
}
|
||||
// Happens for function pointer type arguments for example.
|
||||
for (FunctionProtoType::arg_type_iterator Arg = Proto->arg_type_begin(),
|
||||
ArgEnd = Proto->arg_type_end();
|
||||
Arg != ArgEnd; ++Arg)
|
||||
mangleArgumentType(*Arg, Range);
|
||||
// <builtin-type> ::= Z # ellipsis
|
||||
if (Proto->isVariadic())
|
||||
Out << 'Z';
|
||||
|
@ -1431,8 +1438,7 @@ void MicrosoftCXXNameMangler::mangleType(const IncompleteArrayType *T,
|
|||
SourceRange) {
|
||||
llvm_unreachable("Should have been special cased");
|
||||
}
|
||||
void MicrosoftCXXNameMangler::mangleArrayType(const ArrayType *T,
|
||||
Qualifiers Quals) {
|
||||
void MicrosoftCXXNameMangler::mangleArrayType(const ArrayType *T) {
|
||||
QualType ElementTy(T, 0);
|
||||
SmallVector<llvm::APInt, 3> Dimensions;
|
||||
for (;;) {
|
||||
|
@ -1471,8 +1477,7 @@ void MicrosoftCXXNameMangler::mangleArrayType(const ArrayType *T,
|
|||
mangleNumber(Dimensions.size());
|
||||
for (unsigned Dim = 0; Dim < Dimensions.size(); ++Dim)
|
||||
mangleNumber(Dimensions[Dim].getLimitedValue());
|
||||
mangleType(getASTContext().getQualifiedType(ElementTy.getTypePtr(), Quals),
|
||||
SourceRange(), QMM_Escape);
|
||||
mangleType(ElementTy, SourceRange(), QMM_Escape);
|
||||
}
|
||||
|
||||
// <type> ::= <pointer-to-member-type>
|
||||
|
|
|
@ -162,3 +162,45 @@ void foo_volatile(volatile Vector) {}
|
|||
void foo(Vector*, const Vector, const double) {}
|
||||
// CHECK: "\01?foo@@YAXPAY02NQBNN@Z"
|
||||
// X64: "\01?foo@@YAXPEAY02NQEBNN@Z"
|
||||
|
||||
typedef void (*ConstFunPtr)(int *const d);
|
||||
void foo_fnptrconst(ConstFunPtr f) { }
|
||||
// CHECK: "\01?foo_fnptrconst@@YAXP6AXQAH@Z@Z"
|
||||
// X64: "\01?foo_fnptrconst@@YAXP6AXQEAH@Z@Z"
|
||||
|
||||
typedef void (*ArrayFunPtr)(int d[1]);
|
||||
void foo_fnptrarray(ArrayFunPtr f) { }
|
||||
// CHECK: "\01?foo_fnptrarray@@YAXP6AXQAH@Z@Z"
|
||||
// X64: "\01?foo_fnptrarray@@YAXP6AXQEAH@Z@Z"
|
||||
|
||||
void foo_fnptrbackref1(ArrayFunPtr f1, ArrayFunPtr f2) { }
|
||||
// CHECK: "\01?foo_fnptrbackref1@@YAXP6AXQAH@Z1@Z"
|
||||
// X64: "\01?foo_fnptrbackref1@@YAXP6AXQEAH@Z1@Z"
|
||||
|
||||
void foo_fnptrbackref2(ArrayFunPtr f1, ConstFunPtr f2) { }
|
||||
// CHECK: "\01?foo_fnptrbackref2@@YAXP6AXQAH@Z1@Z"
|
||||
// X64: "\01?foo_fnptrbackref2@@YAXP6AXQEAH@Z1@Z"
|
||||
|
||||
typedef void (*NormalFunPtr)(int *d);
|
||||
void foo_fnptrbackref3(ArrayFunPtr f1, NormalFunPtr f2) { }
|
||||
// CHECK: "\01?foo_fnptrbackref3@@YAXP6AXQAH@Z1@Z"
|
||||
// X64: "\01?foo_fnptrbackref3@@YAXP6AXQEAH@Z1@Z"
|
||||
|
||||
void foo_fnptrbackref4(NormalFunPtr f1, ArrayFunPtr f2) { }
|
||||
// CHECK: "\01?foo_fnptrbackref4@@YAXP6AXPAH@Z1@Z"
|
||||
// X64: "\01?foo_fnptrbackref4@@YAXP6AXPEAH@Z1@Z"
|
||||
|
||||
ArrayFunPtr ret_fnptrarray() { return 0; }
|
||||
// CHECK: "\01?ret_fnptrarray@@YAP6AXQAH@ZXZ"
|
||||
// X64: "\01?ret_fnptrarray@@YAP6AXQEAH@ZXZ"
|
||||
|
||||
// Test that we mangle the forward decl when we have a redeclaration with a
|
||||
// slightly different type.
|
||||
void mangle_fwd(char * const x);
|
||||
void mangle_fwd(char * x) {}
|
||||
// CHECK: "\01?mangle_fwd@@YAXQAD@Z"
|
||||
// X64: "\01?mangle_fwd@@YAXQEAD@Z"
|
||||
|
||||
void mangle_no_fwd(char * x) {}
|
||||
// CHECK: "\01?mangle_no_fwd@@YAXPAD@Z"
|
||||
// X64: "\01?mangle_no_fwd@@YAXPEAD@Z"
|
||||
|
|
Loading…
Reference in New Issue