Store a parameter index and function prototype depth in every
parameter node and use this to correctly mangle parameter
references in function template signatures.
A follow-up patch will improve the storage usage of these
fields; here I've just done the lazy thing.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@130669 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp
index 04d705e..c460929 100644
--- a/lib/AST/ItaniumMangle.cpp
+++ b/lib/AST/ItaniumMangle.cpp
@@ -21,6 +21,7 @@
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/ExprCXX.h"
+#include "clang/AST/TypeLoc.h"
#include "clang/Basic/ABI.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
@@ -50,18 +51,16 @@
return 0;
}
-static const CXXMethodDecl *getStructor(const CXXMethodDecl *MD) {
- assert((isa<CXXConstructorDecl>(MD) || isa<CXXDestructorDecl>(MD)) &&
- "Passed in decl is not a ctor or dtor!");
+static const FunctionDecl *getStructor(const FunctionDecl *fn) {
+ if (const FunctionTemplateDecl *ftd = fn->getPrimaryTemplate())
+ return ftd->getTemplatedDecl();
- if (const TemplateDecl *TD = MD->getPrimaryTemplate()) {
- MD = cast<CXXMethodDecl>(TD->getTemplatedDecl());
+ return fn;
+}
- assert((isa<CXXConstructorDecl>(MD) || isa<CXXDestructorDecl>(MD)) &&
- "Templated decl is not a ctor or dtor!");
- }
-
- return MD;
+static const NamedDecl *getStructor(const NamedDecl *decl) {
+ const FunctionDecl *fn = dyn_cast_or_null<FunctionDecl>(decl);
+ return (fn ? getStructor(fn) : decl);
}
static const unsigned UnknownArity = ~0U;
@@ -138,27 +137,75 @@
ItaniumMangleContext &Context;
llvm::raw_ostream &Out;
- const CXXMethodDecl *Structor;
+ /// The "structor" is the top-level declaration being mangled, if
+ /// that's not a template specialization; otherwise it's the pattern
+ /// for that specialization.
+ const NamedDecl *Structor;
unsigned StructorType;
/// SeqID - The next subsitution sequence number.
unsigned SeqID;
+ class FunctionTypeDepthState {
+ unsigned Bits;
+
+ enum { InResultTypeMask = 1 };
+
+ public:
+ FunctionTypeDepthState() : Bits(0) {}
+
+ /// The number of function types we're inside.
+ unsigned getDepth() const {
+ return Bits >> 1;
+ }
+
+ /// True if we're in the return type of the innermost function type.
+ bool isInResultType() const {
+ return Bits & InResultTypeMask;
+ }
+
+ FunctionTypeDepthState push() {
+ FunctionTypeDepthState tmp = *this;
+ Bits = (Bits & ~InResultTypeMask) + 2;
+ return tmp;
+ }
+
+ void enterResultType() {
+ Bits |= InResultTypeMask;
+ }
+
+ void leaveResultType() {
+ Bits &= ~InResultTypeMask;
+ }
+
+ void pop(FunctionTypeDepthState saved) {
+ assert(getDepth() == saved.getDepth() + 1);
+ Bits = saved.Bits;
+ }
+
+ } FunctionTypeDepth;
+
llvm::DenseMap<uintptr_t, unsigned> Substitutions;
ASTContext &getASTContext() const { return Context.getASTContext(); }
public:
- CXXNameMangler(ItaniumMangleContext &C, llvm::raw_ostream &Out_)
- : Context(C), Out(Out_), Structor(0), StructorType(0), SeqID(0) { }
+ CXXNameMangler(ItaniumMangleContext &C, llvm::raw_ostream &Out_,
+ const NamedDecl *D = 0)
+ : Context(C), Out(Out_), Structor(getStructor(D)), StructorType(0),
+ SeqID(0) {
+ // These can't be mangled without a ctor type or dtor type.
+ assert(!D || (!isa<CXXDestructorDecl>(D) &&
+ !isa<CXXConstructorDecl>(D)));
+ }
CXXNameMangler(ItaniumMangleContext &C, llvm::raw_ostream &Out_,
const CXXConstructorDecl *D, CXXCtorType Type)
: Context(C), Out(Out_), Structor(getStructor(D)), StructorType(Type),
- SeqID(0) { }
+ SeqID(0) { }
CXXNameMangler(ItaniumMangleContext &C, llvm::raw_ostream &Out_,
const CXXDestructorDecl *D, CXXDtorType Type)
: Context(C), Out(Out_), Structor(getStructor(D)), StructorType(Type),
- SeqID(0) { }
+ SeqID(0) { }
#if MANGLE_CHECKER
~CXXNameMangler() {
@@ -272,6 +319,8 @@
void mangleTemplateArg(const NamedDecl *P, const TemplateArgument &A);
void mangleTemplateParameter(unsigned Index);
+
+ void mangleFunctionParam(const ParmVarDecl *parm);
};
}
@@ -1473,8 +1522,7 @@
case BuiltinType::Dependent:
case BuiltinType::BoundMember:
case BuiltinType::UnknownAny:
- assert(false &&
- "Overloaded and dependent types shouldn't get to name mangling");
+ llvm_unreachable("mangling a placeholder type");
break;
case BuiltinType::ObjCId: Out << "11objc_object"; break;
case BuiltinType::ObjCClass: Out << "10objc_class"; break;
@@ -1499,13 +1547,22 @@
// We should never be mangling something without a prototype.
const FunctionProtoType *Proto = cast<FunctionProtoType>(T);
+ // Record that we're in a function type. See mangleFunctionParam
+ // for details on what we're trying to achieve here.
+ FunctionTypeDepthState saved = FunctionTypeDepth.push();
+
// <bare-function-type> ::= <signature type>+
- if (MangleReturnType)
+ if (MangleReturnType) {
+ FunctionTypeDepth.enterResultType();
mangleType(Proto->getResultType());
+ FunctionTypeDepth.leaveResultType();
+ }
if (Proto->getNumArgs() == 0 && !Proto->isVariadic()) {
// <builtin-type> ::= v # void
Out << 'v';
+
+ FunctionTypeDepth.pop(saved);
return;
}
@@ -1514,6 +1571,8 @@
Arg != ArgEnd; ++Arg)
mangleType(*Arg);
+ FunctionTypeDepth.pop(saved);
+
// <builtin-type> ::= z # ellipsis
if (Proto->isVariadic())
Out << 'z';
@@ -2227,6 +2286,10 @@
Out << 'E';
break;
+ case Decl::ParmVar:
+ mangleFunctionParam(cast<ParmVarDecl>(D));
+ break;
+
case Decl::EnumConstant: {
const EnumConstantDecl *ED = cast<EnumConstantDecl>(D);
mangleIntegerLiteral(ED->getType(), ED->getInitVal());
@@ -2388,6 +2451,67 @@
}
}
+/// Mangle an expression which refers to a parameter variable.
+///
+/// <expression> ::= <function-param>
+/// <function-param> ::= fp <top-level CV-qualifiers> _ # L == 0, I == 0
+/// <function-param> ::= fp <top-level CV-qualifiers>
+/// <parameter-2 non-negative number> _ # L == 0, I > 0
+/// <function-param> ::= fL <L-1 non-negative number>
+/// p <top-level CV-qualifiers> _ # L > 0, I == 0
+/// <function-param> ::= fL <L-1 non-negative number>
+/// p <top-level CV-qualifiers>
+/// <I-1 non-negative number> _ # L > 0, I > 0
+///
+/// L is the nesting depth of the parameter, defined as 1 if the
+/// parameter comes from the innermost function prototype scope
+/// enclosing the current context, 2 if from the next enclosing
+/// function prototype scope, and so on, with one special case: if
+/// we've processed the full parameter clause for the innermost
+/// function type, then L is one less. This definition conveniently
+/// makes it irrelevant whether a function's result type was written
+/// trailing or leading, but is otherwise overly complicated; the
+/// numbering was first designed without considering references to
+/// parameter in locations other than return types, and then the
+/// mangling had to be generalized without changing the existing
+/// manglings.
+///
+/// I is the zero-based index of the parameter within its parameter
+/// declaration clause. Note that the original ABI document describes
+/// this using 1-based ordinals.
+void CXXNameMangler::mangleFunctionParam(const ParmVarDecl *parm) {
+ unsigned parmDepth = parm->getFunctionScopeDepth();
+ unsigned parmIndex = parm->getFunctionScopeIndex();
+
+ // Compute 'L'.
+ // parmDepth does not include the declaring function prototype.
+ // FunctionTypeDepth does account for that.
+ assert(parmDepth < FunctionTypeDepth.getDepth());
+ unsigned nestingDepth = FunctionTypeDepth.getDepth() - parmDepth;
+ if (FunctionTypeDepth.isInResultType())
+ nestingDepth--;
+
+ if (nestingDepth == 0) {
+ Out << "fp";
+ } else {
+ Out << "fL" << (nestingDepth - 1) << 'p';
+ }
+
+ // Top-level qualifiers. We don't have to worry about arrays here,
+ // because parameters declared as arrays should already have been
+ // tranformed to have pointer type. FIXME: apparently these don't
+ // get mangled if used as an rvalue of a known non-class type?
+ assert(!parm->getType()->isArrayType()
+ && "parameter's type is still an array type?");
+ mangleQualifiers(parm->getType().getQualifiers());
+
+ // Parameter index.
+ if (parmIndex != 0) {
+ Out << (parmIndex - 1);
+ }
+ Out << '_';
+}
+
void CXXNameMangler::mangleCXXCtorType(CXXCtorType T) {
// <ctor-dtor-name> ::= C1 # complete object constructor
// ::= C2 # base object constructor
@@ -2794,7 +2918,7 @@
getASTContext().getSourceManager(),
"Mangling declaration");
- CXXNameMangler Mangler(*this, Out);
+ CXXNameMangler Mangler(*this, Out, D);
return Mangler.mangle(D);
}