Skip to content

Commit

Permalink
AST: Mangle reference temporaries reliably
Browse files Browse the repository at this point in the history
Summary:
Previously, we would generate a single name for all reference
temporaries and allow LLVM to rename them for us.  Instead, number the
reference temporaries as we build them in Sema.

Reviewers: rsmith

Subscribers: cfe-commits

Differential Revision: http://reviews.llvm.org/D3554

llvm-svn: 207776
  • Loading branch information
majnemer committed May 1, 2014
1 parent 0db806b commit daff370
Show file tree
Hide file tree
Showing 14 changed files with 184 additions and 122 deletions.
59 changes: 41 additions & 18 deletions clang/include/clang/AST/ExprCXX.h
Expand Up @@ -3784,39 +3784,51 @@ class FunctionParmPackExpr : public Expr {
/// temporary. When either happens, the expression will also track the
/// declaration which is responsible for the lifetime extension.
class MaterializeTemporaryExpr : public Expr {
public:
/// \brief The temporary-generating expression whose value will be
/// materialized.
Stmt *Temporary;
private:
struct ExtraState {
/// \brief The temporary-generating expression whose value will be
/// materialized.
Stmt *Temporary;

/// \brief The declaration which lifetime-extended this reference, if any.
/// Either a VarDecl, or (for a ctor-initializer) a FieldDecl.
const ValueDecl *ExtendingDecl;
/// \brief The declaration which lifetime-extended this reference, if any.
/// Either a VarDecl, or (for a ctor-initializer) a FieldDecl.
const ValueDecl *ExtendingDecl;

unsigned ManglingNumber;
};
llvm::PointerUnion<Stmt *, ExtraState *> State;

friend class ASTStmtReader;
friend class ASTStmtWriter;

void initializeExtraState(const ValueDecl *ExtendedBy,
unsigned ManglingNumber);

public:
MaterializeTemporaryExpr(QualType T, Expr *Temporary,
bool BoundToLvalueReference,
const ValueDecl *ExtendedBy)
bool BoundToLvalueReference)
: Expr(MaterializeTemporaryExprClass, T,
BoundToLvalueReference? VK_LValue : VK_XValue, OK_Ordinary,
Temporary->isTypeDependent(), Temporary->isValueDependent(),
Temporary->isInstantiationDependent(),
Temporary->containsUnexpandedParameterPack()),
Temporary(Temporary), ExtendingDecl(ExtendedBy) {
}
State(Temporary) {}

MaterializeTemporaryExpr(EmptyShell Empty)
: Expr(MaterializeTemporaryExprClass, Empty) { }

Stmt *getTemporary() const {
return State.is<Stmt *>() ? State.get<Stmt *>()
: State.get<ExtraState *>()->Temporary;
}

/// \brief Retrieve the temporary-generating subexpression whose value will
/// be materialized into a glvalue.
Expr *GetTemporaryExpr() const { return static_cast<Expr *>(Temporary); }
Expr *GetTemporaryExpr() const { return static_cast<Expr *>(getTemporary()); }

/// \brief Retrieve the storage duration for the materialized temporary.
StorageDuration getStorageDuration() const {
const ValueDecl *ExtendingDecl = getExtendingDecl();
if (!ExtendingDecl)
return SD_FullExpression;
// FIXME: This is not necessarily correct for a temporary materialized
Expand All @@ -3828,10 +3840,15 @@ class MaterializeTemporaryExpr : public Expr {

/// \brief Get the declaration which triggered the lifetime-extension of this
/// temporary, if any.
const ValueDecl *getExtendingDecl() const { return ExtendingDecl; }
const ValueDecl *getExtendingDecl() const {
return State.is<Stmt *>() ? nullptr
: State.get<ExtraState *>()->ExtendingDecl;
}

void setExtendingDecl(const ValueDecl *ExtendedBy, unsigned ManglingNumber);

void setExtendingDecl(const ValueDecl *ExtendedBy) {
ExtendingDecl = ExtendedBy;
unsigned getManglingNumber() const {
return State.is<Stmt *>() ? 0 : State.get<ExtraState *>()->ManglingNumber;
}

/// \brief Determine whether this materialized temporary is bound to an
Expand All @@ -3841,18 +3858,24 @@ class MaterializeTemporaryExpr : public Expr {
}

SourceLocation getLocStart() const LLVM_READONLY {
return Temporary->getLocStart();
return getTemporary()->getLocStart();
}
SourceLocation getLocEnd() const LLVM_READONLY {
return Temporary->getLocEnd();
return getTemporary()->getLocEnd();
}

static bool classof(const Stmt *T) {
return T->getStmtClass() == MaterializeTemporaryExprClass;
}

// Iterators
child_range children() { return child_range(&Temporary, &Temporary + 1); }
child_range children() {
if (State.is<Stmt *>())
return child_range(State.getAddrOfPtr1(), State.getAddrOfPtr1() + 1);

auto ES = State.get<ExtraState *>();
return child_range(&ES->Temporary, &ES->Temporary + 1);
}
};

} // end namespace clang
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/AST/Mangle.h
Expand Up @@ -130,6 +130,7 @@ class MangleContext {
const ThisAdjustment &ThisAdjustment,
raw_ostream &) = 0;
virtual void mangleReferenceTemporary(const VarDecl *D,
unsigned ManglingNumber,
raw_ostream &) = 0;
virtual void mangleCXXRTTI(QualType T, raw_ostream &) = 0;
virtual void mangleCXXRTTIName(QualType T, raw_ostream &) = 0;
Expand Down
15 changes: 10 additions & 5 deletions clang/include/clang/Sema/Initialization.h
Expand Up @@ -103,6 +103,9 @@ class InitializedEntity {
/// \brief The type of the object or reference being initialized.
QualType Type;

/// \brief The mangling number for the next reference temporary to be created.
mutable unsigned ManglingNumber;

struct LN {
/// \brief When Kind == EK_Result, EK_Exception, EK_New, the
/// location of the 'return', 'throw', or 'new' keyword,
Expand Down Expand Up @@ -155,19 +158,19 @@ class InitializedEntity {
struct C Capture;
};

InitializedEntity() { }
InitializedEntity() : ManglingNumber(0) {}

/// \brief Create the initialization entity for a variable.
InitializedEntity(VarDecl *Var)
: Kind(EK_Variable), Parent(0), Type(Var->getType()),
: Kind(EK_Variable), Parent(0), Type(Var->getType()), ManglingNumber(0),
VariableOrMember(Var) { }

/// \brief Create the initialization entity for the result of a
/// function, throwing an object, performing an explicit cast, or
/// initializing a parameter for which there is no declaration.
InitializedEntity(EntityKind Kind, SourceLocation Loc, QualType Type,
bool NRVO = false)
: Kind(Kind), Parent(0), Type(Type)
: Kind(Kind), Parent(0), Type(Type), ManglingNumber(0)
{
LocAndNRVO.Location = Loc.getRawEncoding();
LocAndNRVO.NRVO = NRVO;
Expand All @@ -176,15 +179,15 @@ class InitializedEntity {
/// \brief Create the initialization entity for a member subobject.
InitializedEntity(FieldDecl *Member, const InitializedEntity *Parent)
: Kind(EK_Member), Parent(Parent), Type(Member->getType()),
VariableOrMember(Member) { }
ManglingNumber(0), VariableOrMember(Member) { }

/// \brief Create the initialization entity for an array element.
InitializedEntity(ASTContext &Context, unsigned Index,
const InitializedEntity &Parent);

/// \brief Create the initialization entity for a lambda capture.
InitializedEntity(IdentifierInfo *VarID, QualType FieldType, SourceLocation Loc)
: Kind(EK_LambdaCapture), Parent(0), Type(FieldType)
: Kind(EK_LambdaCapture), Parent(0), Type(FieldType), ManglingNumber(0)
{
Capture.VarID = VarID;
Capture.Location = Loc.getRawEncoding();
Expand Down Expand Up @@ -418,6 +421,8 @@ class InitializedEntity {
Kind = EK_Parameter_CF_Audited;
}

unsigned allocateManglingNumber() const { return ++ManglingNumber; }

/// Dump a representation of the initialized entity to standard error,
/// for debugging purposes.
void dump() const;
Expand Down
19 changes: 19 additions & 0 deletions clang/lib/AST/ExprCXX.cpp
Expand Up @@ -1446,6 +1446,25 @@ FunctionParmPackExpr::CreateEmpty(const ASTContext &Context,
FunctionParmPackExpr(QualType(), 0, SourceLocation(), 0, 0);
}

void MaterializeTemporaryExpr::setExtendingDecl(const ValueDecl *ExtendedBy,
unsigned ManglingNumber) {
// We only need extra state if we have to remember more than just the Stmt.
if (!ExtendedBy)
return;

// We may need to allocate extra storage for the mangling number and the
// extended-by ValueDecl.
if (!State.is<ExtraState *>()) {
auto ES = new (ExtendedBy->getASTContext()) ExtraState;
ES->Temporary = State.get<Stmt *>();
State = ES;
}

auto ES = State.get<ExtraState *>();
ES->ExtendingDecl = ExtendedBy;
ES->ManglingNumber = ManglingNumber;
}

TypeTraitExpr::TypeTraitExpr(QualType T, SourceLocation Loc, TypeTrait Kind,
ArrayRef<TypeSourceInfo *> Args,
SourceLocation RParenLoc,
Expand Down
7 changes: 6 additions & 1 deletion clang/lib/AST/ItaniumMangle.cpp
Expand Up @@ -136,7 +136,8 @@ class ItaniumMangleContextImpl : public ItaniumMangleContext {
void mangleCXXDtorThunk(const CXXDestructorDecl *DD, CXXDtorType Type,
const ThisAdjustment &ThisAdjustment,
raw_ostream &) override;
void mangleReferenceTemporary(const VarDecl *D, raw_ostream &) override;
void mangleReferenceTemporary(const VarDecl *D, unsigned ManglingNumber,
raw_ostream &) override;
void mangleCXXVTable(const CXXRecordDecl *RD, raw_ostream &) override;
void mangleCXXVTT(const CXXRecordDecl *RD, raw_ostream &) override;
void mangleCXXCtorVTable(const CXXRecordDecl *RD, int64_t Offset,
Expand Down Expand Up @@ -3782,12 +3783,16 @@ ItaniumMangleContextImpl::mangleItaniumThreadLocalWrapper(const VarDecl *D,
}

void ItaniumMangleContextImpl::mangleReferenceTemporary(const VarDecl *D,
unsigned ManglingNumber,
raw_ostream &Out) {
// We match the GCC mangling here.
// <special-name> ::= GR <object name>
CXXNameMangler Mangler(*this, Out);
Mangler.getStream() << "_ZGR";
Mangler.mangleName(D);
assert(ManglingNumber > 0 && "Reference temporary mangling number is zero!");
if (ManglingNumber > 1)
Mangler.mangleNumber(ManglingNumber - 2);
}

void ItaniumMangleContextImpl::mangleCXXVTable(const CXXRecordDecl *RD,
Expand Down
4 changes: 3 additions & 1 deletion clang/lib/AST/MicrosoftMangle.cpp
Expand Up @@ -117,7 +117,8 @@ class MicrosoftMangleContextImpl : public MicrosoftMangleContext {
raw_ostream &) override;
void mangleCXXDtor(const CXXDestructorDecl *D, CXXDtorType Type,
raw_ostream &) override;
void mangleReferenceTemporary(const VarDecl *, raw_ostream &) override;
void mangleReferenceTemporary(const VarDecl *, unsigned ManglingNumber,
raw_ostream &) override;
void mangleStaticGuardVariable(const VarDecl *D, raw_ostream &Out) override;
void mangleDynamicInitializer(const VarDecl *D, raw_ostream &Out) override;
void mangleDynamicAtExitDestructor(const VarDecl *D,
Expand Down Expand Up @@ -2267,6 +2268,7 @@ void MicrosoftMangleContextImpl::mangleCXXDtor(const CXXDestructorDecl *D,
}

void MicrosoftMangleContextImpl::mangleReferenceTemporary(const VarDecl *VD,
unsigned,
raw_ostream &) {
unsigned DiagID = getDiags().getCustomDiagID(DiagnosticsEngine::Error,
"cannot mangle this reference temporary yet");
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/CodeGen/CodeGenModule.cpp
Expand Up @@ -2828,7 +2828,8 @@ llvm::Constant *CodeGenModule::GetAddrOfGlobalTemporary(
// we also need to make the temporaries externally-visible).
SmallString<256> Name;
llvm::raw_svector_ostream Out(Name);
getCXXABI().getMangleContext().mangleReferenceTemporary(VD, Out);
getCXXABI().getMangleContext().mangleReferenceTemporary(
VD, E->getManglingNumber(), Out);
Out.flush();

APValue *Value = 0;
Expand Down
3 changes: 1 addition & 2 deletions clang/lib/Sema/SemaCast.cpp
Expand Up @@ -1584,8 +1584,7 @@ static TryCastResult TryConstCast(Sema &Self, ExprResult &SrcExpr,
// This is a const_cast from a class prvalue to an rvalue reference type.
// Materialize a temporary to store the result of the conversion.
SrcExpr = new (Self.Context) MaterializeTemporaryExpr(
SrcType, SrcExpr.take(), /*IsLValueReference*/ false,
/*ExtendingDecl*/ 0);
SrcType, SrcExpr.take(), /*IsLValueReference*/ false);

return TC_Success;
}
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Sema/SemaExpr.cpp
Expand Up @@ -8885,7 +8885,7 @@ QualType Sema::CheckAddressOfOperand(ExprResult &OrigOp, SourceLocation OpLoc) {
return QualType();
// Materialize the temporary as an lvalue so that we can take its address.
OrigOp = op = new (Context)
MaterializeTemporaryExpr(op->getType(), OrigOp.take(), true, 0);
MaterializeTemporaryExpr(op->getType(), OrigOp.take(), true);
} else if (isa<ObjCSelectorExpr>(op)) {
return Context.getPointerType(op->getType());
} else if (lval == Expr::LV_MemberFunction) {
Expand Down

0 comments on commit daff370

Please sign in to comment.