From: Douglas Gregor Date: Tue, 12 Jul 2011 15:18:55 +0000 (+0000) Subject: Improve name mangling for instantiation-dependent types that are not X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=f1588660c109610e6a79c786b83b7c9bbd6ed31e;p=clang 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 . git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@134984 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index d8a92272c8..ef0dbdae03 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -757,6 +757,13 @@ public: 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 /// outer-level parentheses. QualType IgnoreParens() const { diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp index 5b247f2cdd..b07e962871 100644 --- a/lib/AST/ItaniumMangle.cpp +++ b/lib/AST/ItaniumMangle.cpp @@ -319,7 +319,7 @@ private: unsigned NumTemplateArgs); void mangleTemplateArgs(const TemplateParameterList &PL, const TemplateArgumentList &AL); - void mangleTemplateArg(const NamedDecl *P, const TemplateArgument &A); + void mangleTemplateArg(const NamedDecl *P, TemplateArgument A); void mangleUnresolvedTemplateArgs(const TemplateArgument *args, unsigned numArgs); @@ -1596,26 +1596,59 @@ void CXXNameMangler::mangleObjCMethodName(const ObjCMethodDecl *MD) { Context.mangleObjCMethodName(MD, Out); } -void CXXNameMangler::mangleType(QualType nonCanon) { - // Only operate on the canonical type! - QualType canon = nonCanon.getCanonicalType(); - - SplitQualType split = canon.split(); +void CXXNameMangler::mangleType(QualType T) { + // If our type is instantiation-dependent but not dependent, we mangle + // 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(T)) + if (!TST->isTypeAlias()) + break; + + QualType Desugared + = T.getSingleStepDesugaredType(Context.getASTContext()); + if (Desugared == T) + break; + + T = Desugared; + } while (true); + } + SplitQualType split = T.split(); Qualifiers quals = split.second; const Type *ty = split.first; - bool isSubstitutable = quals || !isa(ty); - if (isSubstitutable && mangleSubstitution(canon)) + bool isSubstitutable = quals || !isa(T); + if (isSubstitutable && mangleSubstitution(T)) return; // If we're mangling a qualified array type, push the qualifiers to // the element type. - if (quals && isa(ty)) { - ty = Context.getASTContext().getAsArrayType(canon); + if (quals && isa(T)) { + ty = Context.getASTContext().getAsArrayType(T); quals = Qualifiers(); - // Note that we don't update canon: we want to add the - // substitution at the canonical type. + // Note that we don't update T: we want to add the + // substitution at the original type. } if (quals) { @@ -1640,7 +1673,7 @@ void CXXNameMangler::mangleType(QualType nonCanon) { // Add the substitution. if (isSubstitutable) - addSubstitution(canon); + addSubstitution(T); } void CXXNameMangler::mangleNameOrStandardSubstitution(const NamedDecl *ND) { @@ -2826,12 +2859,15 @@ void CXXNameMangler::mangleTemplateArgs(const TemplateParameterList &PL, } void CXXNameMangler::mangleTemplateArg(const NamedDecl *P, - const TemplateArgument &A) { + TemplateArgument A) { // ::= # type or template // ::= X E # expression // ::= # simple expressions // ::= J * E # argument pack - // ::= sp # pack expansion of (C++0x) + // ::= sp # pack expansion of (C++0x) + if (!A.isInstantiationDependent() || A.isDependent()) + A = Context.getASTContext().getCanonicalTemplateArgument(A); + switch (A.getKind()) { case TemplateArgument::Null: llvm_unreachable("Cannot mangle NULL template argument"); diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 89c00eb850..1f0a37efac 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -180,6 +180,26 @@ QualType QualType::getDesugaredType(QualType T, const ASTContext &Context) { 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(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) { QualifierCollector Qs; diff --git a/test/CodeGenCXX/mangle.cpp b/test/CodeGenCXX/mangle.cpp index 0b3ba639af..453b7b713a 100644 --- a/test/CodeGenCXX/mangle.cpp +++ b/test/CodeGenCXX/mangle.cpp @@ -825,6 +825,15 @@ namespace test34 { // CHECK: define weak_odr void @_ZN6test342f3ILy4EEEvRAplT_Ly8E_i template void f3<4>(int (&)[4 + sizeof(int*)]); + + // Mangling for instantiation-dependent sizeof() expressions as + // template arguments. + template struct A { }; + + template void f4(::test34::A) { } + + // CHECK: define weak_odr void @_ZN6test342f4IiEEvNS_1AIXszstDTplcvT__EcvS2__EEEEE + template void f4(A); } namespace test35 {