Skip to content

Commit

Permalink
Store a parameter index and function prototype depth in every
Browse files Browse the repository at this point in the history
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
  • Loading branch information
rjmccall committed May 1, 2011
1 parent 6857c3e commit fb44de9
Show file tree
Hide file tree
Showing 14 changed files with 384 additions and 77 deletions.
33 changes: 31 additions & 2 deletions include/clang/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -1137,14 +1137,27 @@ class ImplicitParamDecl : public VarDecl {
static bool classofKind(Kind K) { return K == ImplicitParam; }
};

/// ParmVarDecl - Represent a parameter to a function.
/// ParmVarDecl - Represents a parameter to a function.
class ParmVarDecl : public VarDecl {
// FIXME: I'm convinced that there's some reasonable way to encode
// these that doesn't require extra storage, but I don't know what
// it is right now.

/// The number of function parameter scopes enclosing the function
/// parameter scope in which this parameter was declared.
unsigned FunctionScopeDepth : 16;

/// The number of parameters preceding this parameter in the
/// function parameter scope in which it was declared.
unsigned FunctionScopeIndex : 16;

protected:
ParmVarDecl(Kind DK, DeclContext *DC, SourceLocation StartLoc,
SourceLocation IdLoc, IdentifierInfo *Id,
QualType T, TypeSourceInfo *TInfo,
StorageClass S, StorageClass SCAsWritten, Expr *DefArg)
: VarDecl(DK, DC, StartLoc, IdLoc, Id, T, TInfo, S, SCAsWritten) {
: VarDecl(DK, DC, StartLoc, IdLoc, Id, T, TInfo, S, SCAsWritten),
FunctionScopeDepth(0), FunctionScopeIndex(0) {
assert(ParmVarDeclBits.ObjCDeclQualifier == OBJC_TQ_None);
assert(ParmVarDeclBits.HasInheritedDefaultArg == false);
assert(ParmVarDeclBits.IsKNRPromoted == false);
Expand All @@ -1159,6 +1172,22 @@ class ParmVarDecl : public VarDecl {
StorageClass S, StorageClass SCAsWritten,
Expr *DefArg);

void setScopeInfo(unsigned scopeDepth, unsigned parameterIndex) {
FunctionScopeDepth = scopeDepth;
assert(FunctionScopeDepth == scopeDepth && "truncation!");

FunctionScopeIndex = parameterIndex;
assert(FunctionScopeIndex == parameterIndex && "truncation!");
}

unsigned getFunctionScopeDepth() const {
return FunctionScopeDepth;
}

unsigned getFunctionScopeIndex() const {
return FunctionScopeIndex;
}

ObjCDeclQualifier getObjCDeclQualifier() const {
return ObjCDeclQualifier(ParmVarDeclBits.ObjCDeclQualifier);
}
Expand Down
53 changes: 23 additions & 30 deletions include/clang/Sema/Scope.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

#include "clang/Basic/Diagnostic.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"

namespace clang {

Expand Down Expand Up @@ -93,6 +94,14 @@ class Scope {
/// interrelates with other control flow statements.
unsigned short Flags;

/// PrototypeDepth - This is the number of function prototype scopes
/// enclosing this scope, including this scope.
unsigned short PrototypeDepth;

/// PrototypeIndex - This is the number of parameters currently
/// declared in this scope.
unsigned short PrototypeIndex;

/// FnParent - If this scope has a parent scope that is a function body, this
/// pointer is non-null and points to it. This is used for label processing.
Scope *FnParent;
Expand Down Expand Up @@ -196,6 +205,19 @@ class Scope {
Scope *getTemplateParamParent() { return TemplateParamParent; }
const Scope *getTemplateParamParent() const { return TemplateParamParent; }

/// Returns the number of function prototype scopes in this scope
/// chain.
unsigned getFunctionPrototypeDepth() const {
return PrototypeDepth;
}

/// Return the number of parameters declared in this function
/// prototype, increasing it by one for the next call.
unsigned getNextFunctionPrototypeIndex() {
assert(isFunctionPrototypeScope());
return PrototypeIndex++;
}

typedef DeclSetTy::iterator decl_iterator;
decl_iterator decl_begin() const { return DeclsInScope.begin(); }
decl_iterator decl_end() const { return DeclsInScope.end(); }
Expand Down Expand Up @@ -302,36 +324,7 @@ class Scope {

/// Init - This is used by the parser to implement scope caching.
///
void Init(Scope *Parent, unsigned ScopeFlags) {
AnyParent = Parent;
Depth = AnyParent ? AnyParent->Depth+1 : 0;
Flags = ScopeFlags;

if (AnyParent) {
FnParent = AnyParent->FnParent;
BreakParent = AnyParent->BreakParent;
ContinueParent = AnyParent->ContinueParent;
ControlParent = AnyParent->ControlParent;
BlockParent = AnyParent->BlockParent;
TemplateParamParent = AnyParent->TemplateParamParent;
} else {
FnParent = BreakParent = ContinueParent = BlockParent = 0;
ControlParent = 0;
TemplateParamParent = 0;
}

// If this scope is a function or contains breaks/continues, remember it.
if (Flags & FnScope) FnParent = this;
if (Flags & BreakScope) BreakParent = this;
if (Flags & ContinueScope) ContinueParent = this;
if (Flags & ControlScope) ControlParent = this;
if (Flags & BlockScope) BlockParent = this;
if (Flags & TemplateParamScope) TemplateParamParent = this;
DeclsInScope.clear();
UsingDirectives.clear();
Entity = 0;
ErrorTrap.reset();
}
void Init(Scope *parent, unsigned flags);
};

} // end namespace clang
Expand Down
1 change: 1 addition & 0 deletions include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -4527,6 +4527,7 @@ class Sema {
DeclarationName Entity);
ParmVarDecl *SubstParmVarDecl(ParmVarDecl *D,
const MultiLevelTemplateArgumentList &TemplateArgs,
int indexAdjustment,
llvm::Optional<unsigned> NumExpansions);
bool SubstParmTypes(SourceLocation Loc,
ParmVarDecl **Params, unsigned NumParams,
Expand Down
162 changes: 143 additions & 19 deletions lib/AST/ItaniumMangle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -50,18 +51,16 @@ static const CXXRecordDecl *GetLocalClassDecl(const NamedDecl *ND) {
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());

assert((isa<CXXConstructorDecl>(MD) || isa<CXXDestructorDecl>(MD)) &&
"Templated decl is not a ctor or dtor!");
}
return fn;
}

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;
Expand Down Expand Up @@ -138,27 +137,75 @@ class CXXNameMangler {
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() {
Expand Down Expand Up @@ -272,6 +319,8 @@ class CXXNameMangler {
void mangleTemplateArg(const NamedDecl *P, const TemplateArgument &A);

void mangleTemplateParameter(unsigned Index);

void mangleFunctionParam(const ParmVarDecl *parm);
};

}
Expand Down Expand Up @@ -1473,8 +1522,7 @@ void CXXNameMangler::mangleType(const BuiltinType *T) {
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;
Expand All @@ -1499,13 +1547,22 @@ void CXXNameMangler::mangleBareFunctionType(const FunctionType *T,
// 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;
}

Expand All @@ -1514,6 +1571,8 @@ void CXXNameMangler::mangleBareFunctionType(const FunctionType *T,
Arg != ArgEnd; ++Arg)
mangleType(*Arg);

FunctionTypeDepth.pop(saved);

// <builtin-type> ::= z # ellipsis
if (Proto->isVariadic())
Out << 'z';
Expand Down Expand Up @@ -2227,6 +2286,10 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
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());
Expand Down Expand Up @@ -2388,6 +2451,67 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
}
}

/// 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
Expand Down Expand Up @@ -2794,7 +2918,7 @@ void ItaniumMangleContext::mangleName(const NamedDecl *D,
getASTContext().getSourceManager(),
"Mangling declaration");

CXXNameMangler Mangler(*this, Out);
CXXNameMangler Mangler(*this, Out, D);
return Mangler.mangle(D);
}

Expand Down
Loading

0 comments on commit fb44de9

Please sign in to comment.