forked from OSchip/llvm-project
Improve name mangling for instantiation-dependent types that are not
dependent. This covers an odd class of types such as int (&)[sizeof(sizeof(T() + T()))]; which involve template parameters but, because of some trick typically involving a form of expression that is never type-dependent, resolve down to a non-dependent type. Such types need to be mangled essentially as they were written in the source code (involving template parameters), rather than via their canonical type. In general, instantiation-dependent types should be mangled as they were written in the source. However, since we can't do that now without non-trivial refactoring of the AST (see the new FIXME), I've gone for this partial solution: only use the as-written-in-the-source mangling for these strange types that are instantiation-dependent but not dependent. This provides better compatibility with previous incarnations of Clang and with GCC. In the future, we'd like to get this right. Fixes <rdar://problem/9663282>. llvm-svn: 134984
This commit is contained in:
parent
a4fb836f06
commit
2207ec273a
|
@ -757,6 +757,13 @@ public:
|
||||||
return getSplitDesugaredType(*this);
|
return getSplitDesugaredType(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// \brief Return the specified type with one level of "sugar" removed from
|
||||||
|
/// the type.
|
||||||
|
///
|
||||||
|
/// This routine takes off the first typedef, typeof, etc. If the outer level
|
||||||
|
/// of the type is already concrete, it returns it unmodified.
|
||||||
|
QualType getSingleStepDesugaredType(const ASTContext &Context) const;
|
||||||
|
|
||||||
/// IgnoreParens - Returns the specified type after dropping any
|
/// IgnoreParens - Returns the specified type after dropping any
|
||||||
/// outer-level parentheses.
|
/// outer-level parentheses.
|
||||||
QualType IgnoreParens() const {
|
QualType IgnoreParens() const {
|
||||||
|
|
|
@ -319,7 +319,7 @@ private:
|
||||||
unsigned NumTemplateArgs);
|
unsigned NumTemplateArgs);
|
||||||
void mangleTemplateArgs(const TemplateParameterList &PL,
|
void mangleTemplateArgs(const TemplateParameterList &PL,
|
||||||
const TemplateArgumentList &AL);
|
const TemplateArgumentList &AL);
|
||||||
void mangleTemplateArg(const NamedDecl *P, const TemplateArgument &A);
|
void mangleTemplateArg(const NamedDecl *P, TemplateArgument A);
|
||||||
void mangleUnresolvedTemplateArgs(const TemplateArgument *args,
|
void mangleUnresolvedTemplateArgs(const TemplateArgument *args,
|
||||||
unsigned numArgs);
|
unsigned numArgs);
|
||||||
|
|
||||||
|
@ -1596,26 +1596,59 @@ void CXXNameMangler::mangleObjCMethodName(const ObjCMethodDecl *MD) {
|
||||||
Context.mangleObjCMethodName(MD, Out);
|
Context.mangleObjCMethodName(MD, Out);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CXXNameMangler::mangleType(QualType nonCanon) {
|
void CXXNameMangler::mangleType(QualType T) {
|
||||||
// Only operate on the canonical type!
|
// If our type is instantiation-dependent but not dependent, we mangle
|
||||||
QualType canon = nonCanon.getCanonicalType();
|
// it as it was written in the source, removing any top-level sugar.
|
||||||
|
// Otherwise, use the canonical type.
|
||||||
|
//
|
||||||
|
// FIXME: This is an approximation of the instantiation-dependent name
|
||||||
|
// mangling rules, since we should really be using the type as written and
|
||||||
|
// augmented via semantic analysis (i.e., with implicit conversions and
|
||||||
|
// default template arguments) for any instantiation-dependent type.
|
||||||
|
// Unfortunately, that requires several changes to our AST:
|
||||||
|
// - Instantiation-dependent TemplateSpecializationTypes will need to be
|
||||||
|
// uniqued, so that we can handle substitutions properly
|
||||||
|
// - Default template arguments will need to be represented in the
|
||||||
|
// TemplateSpecializationType, since they need to be mangled even though
|
||||||
|
// they aren't written.
|
||||||
|
// - Conversions on non-type template arguments need to be expressed, since
|
||||||
|
// they can affect the mangling of sizeof/alignof.
|
||||||
|
if (!T->isInstantiationDependentType() || T->isDependentType())
|
||||||
|
T = T.getCanonicalType();
|
||||||
|
else {
|
||||||
|
// Desugar any types that are purely sugar.
|
||||||
|
do {
|
||||||
|
// Don't desugar through template specialization types that aren't
|
||||||
|
// type aliases. We need to mangle the template arguments as written.
|
||||||
|
if (const TemplateSpecializationType *TST
|
||||||
|
= dyn_cast<TemplateSpecializationType>(T))
|
||||||
|
if (!TST->isTypeAlias())
|
||||||
|
break;
|
||||||
|
|
||||||
SplitQualType split = canon.split();
|
QualType Desugared
|
||||||
|
= T.getSingleStepDesugaredType(Context.getASTContext());
|
||||||
|
if (Desugared == T)
|
||||||
|
break;
|
||||||
|
|
||||||
|
T = Desugared;
|
||||||
|
} while (true);
|
||||||
|
}
|
||||||
|
SplitQualType split = T.split();
|
||||||
Qualifiers quals = split.second;
|
Qualifiers quals = split.second;
|
||||||
const Type *ty = split.first;
|
const Type *ty = split.first;
|
||||||
|
|
||||||
bool isSubstitutable = quals || !isa<BuiltinType>(ty);
|
bool isSubstitutable = quals || !isa<BuiltinType>(T);
|
||||||
if (isSubstitutable && mangleSubstitution(canon))
|
if (isSubstitutable && mangleSubstitution(T))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// If we're mangling a qualified array type, push the qualifiers to
|
// If we're mangling a qualified array type, push the qualifiers to
|
||||||
// the element type.
|
// the element type.
|
||||||
if (quals && isa<ArrayType>(ty)) {
|
if (quals && isa<ArrayType>(T)) {
|
||||||
ty = Context.getASTContext().getAsArrayType(canon);
|
ty = Context.getASTContext().getAsArrayType(T);
|
||||||
quals = Qualifiers();
|
quals = Qualifiers();
|
||||||
|
|
||||||
// Note that we don't update canon: we want to add the
|
// Note that we don't update T: we want to add the
|
||||||
// substitution at the canonical type.
|
// substitution at the original type.
|
||||||
}
|
}
|
||||||
|
|
||||||
if (quals) {
|
if (quals) {
|
||||||
|
@ -1640,7 +1673,7 @@ void CXXNameMangler::mangleType(QualType nonCanon) {
|
||||||
|
|
||||||
// Add the substitution.
|
// Add the substitution.
|
||||||
if (isSubstitutable)
|
if (isSubstitutable)
|
||||||
addSubstitution(canon);
|
addSubstitution(T);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CXXNameMangler::mangleNameOrStandardSubstitution(const NamedDecl *ND) {
|
void CXXNameMangler::mangleNameOrStandardSubstitution(const NamedDecl *ND) {
|
||||||
|
@ -2826,12 +2859,15 @@ void CXXNameMangler::mangleTemplateArgs(const TemplateParameterList &PL,
|
||||||
}
|
}
|
||||||
|
|
||||||
void CXXNameMangler::mangleTemplateArg(const NamedDecl *P,
|
void CXXNameMangler::mangleTemplateArg(const NamedDecl *P,
|
||||||
const TemplateArgument &A) {
|
TemplateArgument A) {
|
||||||
// <template-arg> ::= <type> # type or template
|
// <template-arg> ::= <type> # type or template
|
||||||
// ::= X <expression> E # expression
|
// ::= X <expression> E # expression
|
||||||
// ::= <expr-primary> # simple expressions
|
// ::= <expr-primary> # simple expressions
|
||||||
// ::= J <template-arg>* E # argument pack
|
// ::= J <template-arg>* E # argument pack
|
||||||
// ::= sp <expression> # pack expansion of (C++0x)
|
// ::= sp <expression> # pack expansion of (C++0x)
|
||||||
|
if (!A.isInstantiationDependent() || A.isDependent())
|
||||||
|
A = Context.getASTContext().getCanonicalTemplateArgument(A);
|
||||||
|
|
||||||
switch (A.getKind()) {
|
switch (A.getKind()) {
|
||||||
case TemplateArgument::Null:
|
case TemplateArgument::Null:
|
||||||
llvm_unreachable("Cannot mangle NULL template argument");
|
llvm_unreachable("Cannot mangle NULL template argument");
|
||||||
|
|
|
@ -180,6 +180,26 @@ QualType QualType::getDesugaredType(QualType T, const ASTContext &Context) {
|
||||||
return Context.getQualifiedType(split.first, split.second);
|
return Context.getQualifiedType(split.first, split.second);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QualType QualType::getSingleStepDesugaredType(const ASTContext &Context) const {
|
||||||
|
QualifierCollector Qs;
|
||||||
|
|
||||||
|
const Type *CurTy = Qs.strip(*this);
|
||||||
|
switch (CurTy->getTypeClass()) {
|
||||||
|
#define ABSTRACT_TYPE(Class, Parent)
|
||||||
|
#define TYPE(Class, Parent) \
|
||||||
|
case Type::Class: { \
|
||||||
|
const Class##Type *Ty = cast<Class##Type>(CurTy); \
|
||||||
|
if (!Ty->isSugared()) \
|
||||||
|
return *this; \
|
||||||
|
return Context.getQualifiedType(Ty->desugar(), Qs); \
|
||||||
|
break; \
|
||||||
|
}
|
||||||
|
#include "clang/AST/TypeNodes.def"
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
SplitQualType QualType::getSplitDesugaredType(QualType T) {
|
SplitQualType QualType::getSplitDesugaredType(QualType T) {
|
||||||
QualifierCollector Qs;
|
QualifierCollector Qs;
|
||||||
|
|
||||||
|
|
|
@ -825,6 +825,15 @@ namespace test34 {
|
||||||
|
|
||||||
// CHECK: define weak_odr void @_ZN6test342f3ILy4EEEvRAplT_Ly8E_i
|
// CHECK: define weak_odr void @_ZN6test342f3ILy4EEEvRAplT_Ly8E_i
|
||||||
template void f3<4>(int (&)[4 + sizeof(int*)]);
|
template void f3<4>(int (&)[4 + sizeof(int*)]);
|
||||||
|
|
||||||
|
// Mangling for instantiation-dependent sizeof() expressions as
|
||||||
|
// template arguments.
|
||||||
|
template<unsigned> struct A { };
|
||||||
|
|
||||||
|
template<typename T> void f4(::test34::A<sizeof(sizeof(decltype(T() + T())))>) { }
|
||||||
|
|
||||||
|
// CHECK: define weak_odr void @_ZN6test342f4IiEEvNS_1AIXszstDTplcvT__EcvS2__EEEEE
|
||||||
|
template void f4<int>(A<sizeof(sizeof(int))>);
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace test35 {
|
namespace test35 {
|
||||||
|
|
Loading…
Reference in New Issue