AST: Mangle reference temporaries reliably

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
This commit is contained in:
David Majnemer 2014-05-01 17:50:17 +00:00
parent 0db806b7f9
commit daff37013c
14 changed files with 184 additions and 122 deletions

View File

@ -3784,39 +3784,51 @@ public:
/// 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
@ -3828,10 +3840,15 @@ public:
/// \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) {
ExtendingDecl = ExtendedBy;
void setExtendingDecl(const ValueDecl *ExtendedBy, unsigned ManglingNumber);
unsigned getManglingNumber() const {
return State.is<Stmt *>() ? 0 : State.get<ExtraState *>()->ManglingNumber;
}
/// \brief Determine whether this materialized temporary is bound to an
@ -3841,10 +3858,10 @@ public:
}
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) {
@ -3852,7 +3869,13 @@ public:
}
// 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

View File

@ -130,6 +130,7 @@ public:
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;

View File

@ -103,6 +103,9 @@ private:
/// \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,
@ -155,11 +158,11 @@ private:
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
@ -167,7 +170,7 @@ private:
/// 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;
@ -176,7 +179,7 @@ private:
/// \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,
@ -184,7 +187,7 @@ private:
/// \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();
@ -418,6 +421,8 @@ public:
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;

View File

@ -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,

View File

@ -136,7 +136,8 @@ public:
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,
@ -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,

View File

@ -117,7 +117,8 @@ public:
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,
@ -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");

View File

@ -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;

View File

@ -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;
}

View File

@ -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) {

View File

@ -5311,25 +5311,25 @@ InitializedEntityOutlivesFullExpression(const InitializedEntity &Entity) {
/// Determine the declaration which an initialized entity ultimately refers to,
/// for the purpose of lifetime-extending a temporary bound to a reference in
/// the initialization of \p Entity.
static const ValueDecl *
getDeclForTemporaryLifetimeExtension(const InitializedEntity &Entity,
const ValueDecl *FallbackDecl = 0) {
static const InitializedEntity *getEntityForTemporaryLifetimeExtension(
const InitializedEntity *Entity,
const InitializedEntity *FallbackDecl = 0) {
// C++11 [class.temporary]p5:
switch (Entity.getKind()) {
switch (Entity->getKind()) {
case InitializedEntity::EK_Variable:
// The temporary [...] persists for the lifetime of the reference
return Entity.getDecl();
return Entity;
case InitializedEntity::EK_Member:
// For subobjects, we look at the complete object.
if (Entity.getParent())
return getDeclForTemporaryLifetimeExtension(*Entity.getParent(),
Entity.getDecl());
if (Entity->getParent())
return getEntityForTemporaryLifetimeExtension(Entity->getParent(),
Entity);
// except:
// -- A temporary bound to a reference member in a constructor's
// ctor-initializer persists until the constructor exits.
return Entity.getDecl();
return Entity;
case InitializedEntity::EK_Parameter:
case InitializedEntity::EK_Parameter_CF_Audited:
@ -5344,7 +5344,7 @@ getDeclForTemporaryLifetimeExtension(const InitializedEntity &Entity,
// -- A temporary bound to a reference in a new-initializer persists
// until the completion of the full-expression containing the
// new-initializer.
return 0;
return nullptr;
case InitializedEntity::EK_Temporary:
case InitializedEntity::EK_CompoundLiteralInit:
@ -5352,12 +5352,12 @@ getDeclForTemporaryLifetimeExtension(const InitializedEntity &Entity,
// We don't yet know the storage duration of the surrounding temporary.
// Assume it's got full-expression duration for now, it will patch up our
// storage duration if that's not correct.
return 0;
return nullptr;
case InitializedEntity::EK_ArrayElement:
// For subobjects, we look at the complete object.
return getDeclForTemporaryLifetimeExtension(*Entity.getParent(),
FallbackDecl);
return getEntityForTemporaryLifetimeExtension(Entity->getParent(),
FallbackDecl);
case InitializedEntity::EK_Base:
case InitializedEntity::EK_Delegating:
@ -5372,17 +5372,20 @@ getDeclForTemporaryLifetimeExtension(const InitializedEntity &Entity,
case InitializedEntity::EK_Exception:
case InitializedEntity::EK_VectorElement:
case InitializedEntity::EK_ComplexElement:
return 0;
return nullptr;
}
llvm_unreachable("unknown entity kind");
}
static void performLifetimeExtension(Expr *Init, const ValueDecl *ExtendingD);
static void performLifetimeExtension(Expr *Init,
const InitializedEntity *ExtendingEntity);
/// Update a glvalue expression that is used as the initializer of a reference
/// to note that its lifetime is extended.
/// \return \c true if any temporary had its lifetime extended.
static bool performReferenceExtension(Expr *Init, const ValueDecl *ExtendingD) {
static bool
performReferenceExtension(Expr *Init,
const InitializedEntity *ExtendingEntity) {
if (InitListExpr *ILE = dyn_cast<InitListExpr>(Init)) {
if (ILE->getNumInits() == 1 && ILE->isGLValue()) {
// This is just redundant braces around an initializer. Step over it.
@ -5416,8 +5419,9 @@ static bool performReferenceExtension(Expr *Init, const ValueDecl *ExtendingD) {
if (MaterializeTemporaryExpr *ME = dyn_cast<MaterializeTemporaryExpr>(Init)) {
// Update the storage duration of the materialized temporary.
// FIXME: Rebuild the expression instead of mutating it.
ME->setExtendingDecl(ExtendingD);
performLifetimeExtension(ME->GetTemporaryExpr(), ExtendingD);
ME->setExtendingDecl(ExtendingEntity->getDecl(),
ExtendingEntity->allocateManglingNumber());
performLifetimeExtension(ME->GetTemporaryExpr(), ExtendingEntity);
return true;
}
@ -5426,7 +5430,8 @@ static bool performReferenceExtension(Expr *Init, const ValueDecl *ExtendingD) {
/// Update a prvalue expression that is going to be materialized as a
/// lifetime-extended temporary.
static void performLifetimeExtension(Expr *Init, const ValueDecl *ExtendingD) {
static void performLifetimeExtension(Expr *Init,
const InitializedEntity *ExtendingEntity) {
// Dig out the expression which constructs the extended temporary.
SmallVector<const Expr *, 2> CommaLHSs;
SmallVector<SubobjectAdjustment, 2> Adjustments;
@ -5438,14 +5443,14 @@ static void performLifetimeExtension(Expr *Init, const ValueDecl *ExtendingD) {
if (CXXStdInitializerListExpr *ILE =
dyn_cast<CXXStdInitializerListExpr>(Init)) {
performReferenceExtension(ILE->getSubExpr(), ExtendingD);
performReferenceExtension(ILE->getSubExpr(), ExtendingEntity);
return;
}
if (InitListExpr *ILE = dyn_cast<InitListExpr>(Init)) {
if (ILE->getType()->isArrayType()) {
for (unsigned I = 0, N = ILE->getNumInits(); I != N; ++I)
performLifetimeExtension(ILE->getInit(I), ExtendingD);
performLifetimeExtension(ILE->getInit(I), ExtendingEntity);
return;
}
@ -5457,7 +5462,7 @@ static void performLifetimeExtension(Expr *Init, const ValueDecl *ExtendingD) {
// bound to temporaries, those temporaries are also lifetime-extended.
if (RD->isUnion() && ILE->getInitializedFieldInUnion() &&
ILE->getInitializedFieldInUnion()->getType()->isReferenceType())
performReferenceExtension(ILE->getInit(0), ExtendingD);
performReferenceExtension(ILE->getInit(0), ExtendingEntity);
else {
unsigned Index = 0;
for (const auto *I : RD->fields()) {
@ -5467,13 +5472,13 @@ static void performLifetimeExtension(Expr *Init, const ValueDecl *ExtendingD) {
continue;
Expr *SubInit = ILE->getInit(Index);
if (I->getType()->isReferenceType())
performReferenceExtension(SubInit, ExtendingD);
performReferenceExtension(SubInit, ExtendingEntity);
else if (isa<InitListExpr>(SubInit) ||
isa<CXXStdInitializerListExpr>(SubInit))
// This may be either aggregate-initialization of a member or
// initialization of a std::initializer_list object. Either way,
// we should recursively lifetime-extend that initializer.
performLifetimeExtension(SubInit, ExtendingD);
performLifetimeExtension(SubInit, ExtendingEntity);
++Index;
}
}
@ -5759,12 +5764,12 @@ InitializationSequence::Perform(Sema &S,
// Even though we didn't materialize a temporary, the binding may still
// extend the lifetime of a temporary. This happens if we bind a reference
// to the result of a cast to reference type.
if (const ValueDecl *ExtendingDecl =
getDeclForTemporaryLifetimeExtension(Entity)) {
if (performReferenceExtension(CurInit.get(), ExtendingDecl))
warnOnLifetimeExtension(S, Entity, CurInit.get(), false,
ExtendingDecl);
}
if (const InitializedEntity *ExtendingEntity =
getEntityForTemporaryLifetimeExtension(&Entity))
if (performReferenceExtension(CurInit.get(), ExtendingEntity))
warnOnLifetimeExtension(S, Entity, CurInit.get(),
/*IsInitializerList=*/false,
ExtendingEntity->getDecl());
break;
@ -5776,19 +5781,18 @@ InitializationSequence::Perform(Sema &S,
if (S.CheckExceptionSpecCompatibility(CurInit.get(), DestType))
return ExprError();
// Maybe lifetime-extend the temporary's subobjects to match the
// entity's lifetime.
const ValueDecl *ExtendingDecl =
getDeclForTemporaryLifetimeExtension(Entity);
if (ExtendingDecl) {
performLifetimeExtension(CurInit.get(), ExtendingDecl);
warnOnLifetimeExtension(S, Entity, CurInit.get(), false, ExtendingDecl);
}
// Materialize the temporary into memory.
MaterializeTemporaryExpr *MTE = new (S.Context) MaterializeTemporaryExpr(
Entity.getType().getNonReferenceType(), CurInit.get(),
Entity.getType()->isLValueReferenceType(), ExtendingDecl);
Entity.getType()->isLValueReferenceType());
// Maybe lifetime-extend the temporary's subobjects to match the
// entity's lifetime.
if (const InitializedEntity *ExtendingEntity =
getEntityForTemporaryLifetimeExtension(&Entity))
if (performReferenceExtension(MTE, ExtendingEntity))
warnOnLifetimeExtension(S, Entity, CurInit.get(), /*IsInitializerList=*/false,
ExtendingEntity->getDecl());
// If we're binding to an Objective-C object that has lifetime, we
// need cleanups. Likewise if we're extending this temporary to automatic
@ -6176,19 +6180,19 @@ InitializationSequence::Perform(Sema &S,
diag::warn_cxx98_compat_initializer_list_init)
<< CurInit.get()->getSourceRange();
// Maybe lifetime-extend the array temporary's subobjects to match the
// entity's lifetime.
const ValueDecl *ExtendingDecl =
getDeclForTemporaryLifetimeExtension(Entity);
if (ExtendingDecl) {
performLifetimeExtension(CurInit.get(), ExtendingDecl);
warnOnLifetimeExtension(S, Entity, CurInit.get(), true, ExtendingDecl);
}
// Materialize the temporary into memory.
MaterializeTemporaryExpr *MTE = new (S.Context)
MaterializeTemporaryExpr(CurInit.get()->getType(), CurInit.get(),
/*lvalue reference*/ false, ExtendingDecl);
/*BoundToLvalueReference=*/false);
// Maybe lifetime-extend the array temporary's subobjects to match the
// entity's lifetime.
if (const InitializedEntity *ExtendingEntity =
getEntityForTemporaryLifetimeExtension(&Entity))
if (performReferenceExtension(MTE, ExtendingEntity))
warnOnLifetimeExtension(S, Entity, CurInit.get(),
/*IsInitializerList=*/true,
ExtendingEntity->getDecl());
// Wrap it in a construction of a std::initializer_list<T>.
CurInit = S.Owned(

View File

@ -1572,8 +1572,10 @@ void ASTStmtReader::VisitFunctionParmPackExpr(FunctionParmPackExpr *E) {
void ASTStmtReader::VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E) {
VisitExpr(E);
E->Temporary = Reader.ReadSubExpr();
E->ExtendingDecl = ReadDeclAs<ValueDecl>(Record, Idx);
E->State = Reader.ReadSubExpr();
auto VD = ReadDeclAs<ValueDecl>(Record, Idx);
unsigned ManglingNumber = Record[Idx++];
E->setExtendingDecl(VD, ManglingNumber);
}
void ASTStmtReader::VisitOpaqueValueExpr(OpaqueValueExpr *E) {

View File

@ -1567,8 +1567,9 @@ void ASTStmtWriter::VisitFunctionParmPackExpr(FunctionParmPackExpr *E) {
void ASTStmtWriter::VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E) {
VisitExpr(E);
Writer.AddStmt(E->Temporary);
Writer.AddDeclRef(E->ExtendingDecl, Record);
Writer.AddStmt(E->getTemporary());
Writer.AddDeclRef(E->getExtendingDecl(), Record);
Record.push_back(E->getManglingNumber());
Code = serialization::EXPR_MATERIALIZE_TEMPORARY;
}

View File

@ -54,16 +54,16 @@ namespace HiddenVariableTemplateWithConstRef {
const int &use = i<void>;
}
// CHECK: @_ZGRN24VariableTemplateWithPack1sIJLi1ELi2ELi3ELi4EEEE = linkonce_odr constant i32 1
// CHECK: @_ZGRN24VariableTemplateWithPack1sIJLi1ELi2ELi3ELi4EEEE2 = linkonce_odr global {{.*}} { i32* @_ZGRN24VariableTemplateWithPack1sIJLi1ELi2ELi3ELi4EEEE }
// CHECK: @_ZGRN24VariableTemplateWithPack1sIJLi1ELi2ELi3ELi4EEEE1 = linkonce_odr constant i32 1
// CHECK: @_ZGRN24VariableTemplateWithPack1sIJLi1ELi2ELi3ELi4EEEE0 = linkonce_odr global {{.*}} { i32* @_ZGRN24VariableTemplateWithPack1sIJLi1ELi2ELi3ELi4EEEE1 }
// CHECK: @_ZGRN24VariableTemplateWithPack1sIJLi1ELi2ELi3ELi4EEEE3 = linkonce_odr constant i32 2
// CHECK: @_ZGRN24VariableTemplateWithPack1sIJLi1ELi2ELi3ELi4EEEE4 = linkonce_odr global {{.*}} { i32* @_ZGRN24VariableTemplateWithPack1sIJLi1ELi2ELi3ELi4EEEE3 }
// CHECK: @_ZGRN24VariableTemplateWithPack1sIJLi1ELi2ELi3ELi4EEEE2 = linkonce_odr global {{.*}} { i32* @_ZGRN24VariableTemplateWithPack1sIJLi1ELi2ELi3ELi4EEEE3 }
// CHECK: @_ZGRN24VariableTemplateWithPack1sIJLi1ELi2ELi3ELi4EEEE5 = linkonce_odr constant i32 3
// CHECK: @_ZGRN24VariableTemplateWithPack1sIJLi1ELi2ELi3ELi4EEEE6 = linkonce_odr global {{.*}} { i32* @_ZGRN24VariableTemplateWithPack1sIJLi1ELi2ELi3ELi4EEEE5 }
// CHECK: @_ZGRN24VariableTemplateWithPack1sIJLi1ELi2ELi3ELi4EEEE4 = linkonce_odr global {{.*}} { i32* @_ZGRN24VariableTemplateWithPack1sIJLi1ELi2ELi3ELi4EEEE5 }
// CHECK: @_ZGRN24VariableTemplateWithPack1sIJLi1ELi2ELi3ELi4EEEE7 = linkonce_odr constant i32 4
// CHECK: @_ZGRN24VariableTemplateWithPack1sIJLi1ELi2ELi3ELi4EEEE8 = linkonce_odr global {{.*}} { i32* @_ZGRN24VariableTemplateWithPack1sIJLi1ELi2ELi3ELi4EEEE7 }
// CHECK: @_ZGRN24VariableTemplateWithPack1sIJLi1ELi2ELi3ELi4EEEE9 = linkonce_odr global {{.*}} { {{.*}} @_ZGRN24VariableTemplateWithPack1sIJLi1ELi2ELi3ELi4EEEE2, {{.*}} @_ZGRN24VariableTemplateWithPack1sIJLi1ELi2ELi3ELi4EEEE4, {{.*}} @_ZGRN24VariableTemplateWithPack1sIJLi1ELi2ELi3ELi4EEEE6, {{.*}} @_ZGRN24VariableTemplateWithPack1sIJLi1ELi2ELi3ELi4EEEE8 }
// CHECK: @_ZN24VariableTemplateWithPack1pE = global {{.*}} @_ZGRN24VariableTemplateWithPack1sIJLi1ELi2ELi3ELi4EEEE9
// CHECK: @_ZGRN24VariableTemplateWithPack1sIJLi1ELi2ELi3ELi4EEEE6 = linkonce_odr global {{.*}} { i32* @_ZGRN24VariableTemplateWithPack1sIJLi1ELi2ELi3ELi4EEEE7 }
// CHECK: @_ZGRN24VariableTemplateWithPack1sIJLi1ELi2ELi3ELi4EEEE = linkonce_odr global %"struct.VariableTemplateWithPack::S" { {{.*}}* @_ZGRN24VariableTemplateWithPack1sIJLi1ELi2ELi3ELi4EEEE0, {{.*}}* @_ZGRN24VariableTemplateWithPack1sIJLi1ELi2ELi3ELi4EEEE2, {{.*}}* @_ZGRN24VariableTemplateWithPack1sIJLi1ELi2ELi3ELi4EEEE4, {{.*}}* @_ZGRN24VariableTemplateWithPack1sIJLi1ELi2ELi3ELi4EEEE6 }
// CHECK: @_ZN24VariableTemplateWithPack1pE = global {{.*}} @_ZGRN24VariableTemplateWithPack1sIJLi1ELi2ELi3ELi4EEEE
namespace VariableTemplateWithPack {
struct A {
const int &r;

View File

@ -55,76 +55,76 @@ std::initializer_list<std::initializer_list<int>> nested = {
{1, a}, {3, b}, {5, c}
};
// CHECK-STATIC-BL: @_ZGR6nested = private constant [2 x i32] [i32 1, i32 2], align 4
// CHECK-STATIC-BL: @_ZGR6nested0 = private constant [2 x i32] [i32 1, i32 2], align 4
// CHECK-STATIC-BL: @_ZGR6nested1 = private constant [2 x i32] [i32 3, i32 4], align 4
// CHECK-STATIC-BL: @_ZGR6nested2 = private constant [2 x i32] [i32 5, i32 6], align 4
// CHECK-STATIC-BL: @_ZGR6nested3 = private constant [3 x {{.*}}] [
// CHECK-STATIC-BL: {{.*}} { i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested, i32 0, i32 0), i64 2 },
// CHECK-STATIC-BL: @_ZGR6nested = private constant [3 x {{.*}}] [
// CHECK-STATIC-BL: {{.*}} { i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested0, i32 0, i32 0), i64 2 },
// CHECK-STATIC-BL: {{.*}} { i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested1, i32 0, i32 0), i64 2 },
// CHECK-STATIC-BL: {{.*}} { i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested2, i32 0, i32 0), i64 2 }
// CHECK-STATIC-BL: ], align 8
// CHECK-STATIC-BL: @nested = global {{.*}} { {{.*}} getelementptr inbounds ([3 x {{.*}}]* @_ZGR6nested3, i32 0, i32 0), i64 3 }, align 8
// CHECK-STATIC-BL: @nested = global {{.*}} { {{.*}} getelementptr inbounds ([3 x {{.*}}]* @_ZGR6nested, i32 0, i32 0), i64 3 }, align 8
// CHECK-DYNAMIC-BL: @nested = global
// CHECK-DYNAMIC-BL: @_ZGR6nested = private global [3 x
// CHECK-DYNAMIC-BL: @_ZGR6nested0 = private global [2 x i32] zeroinitializer
// CHECK-DYNAMIC-BL: @_ZGR6nested1 = private global [2 x i32] zeroinitializer
// CHECK-DYNAMIC-BL: @_ZGR6nested2 = private global [2 x i32] zeroinitializer
// CHECK-DYNAMIC-BL: @_ZGR6nested3 = private global [2 x i32] zeroinitializer
// CHECK-DYNAMIC-BL: store i32 1, i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested1, i64 0, i64 0)
// CHECK-DYNAMIC-BL: store i32 {{.*}}, i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested1, i64 0, i64 1)
// CHECK-DYNAMIC-BL: store i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested1, i64 0, i64 0),
// CHECK-DYNAMIC-BL: store i32 1, i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested0, i64 0, i64 0)
// CHECK-DYNAMIC-BL: store i32 {{.*}}, i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested0, i64 0, i64 1)
// CHECK-DYNAMIC-BL: store i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested0, i64 0, i64 0),
// CHECK-DYNAMIC-BL: i32** getelementptr inbounds ([3 x {{.*}}]* @_ZGR6nested, i64 0, i64 0, i32 0), align 8
// CHECK-DYNAMIC-BL: store i64 2, i64* getelementptr inbounds ([3 x {{.*}}]* @_ZGR6nested, i64 0, i64 0, i32 1), align 8
// CHECK-DYNAMIC-BL: store i32 3, i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested2, i64 0, i64 0)
// CHECK-DYNAMIC-BL: store i32 {{.*}}, i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested2, i64 0, i64 1)
// CHECK-DYNAMIC-BL: store i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested2, i64 0, i64 0),
// CHECK-DYNAMIC-BL: store i32 3, i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested1, i64 0, i64 0)
// CHECK-DYNAMIC-BL: store i32 {{.*}}, i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested1, i64 0, i64 1)
// CHECK-DYNAMIC-BL: store i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested1, i64 0, i64 0),
// CHECK-DYNAMIC-BL: i32** getelementptr inbounds ([3 x {{.*}}]* @_ZGR6nested, i64 0, i64 1, i32 0), align 8
// CHECK-DYNAMIC-BL: store i64 2, i64* getelementptr inbounds ([3 x {{.*}}]* @_ZGR6nested, i64 0, i64 1, i32 1), align 8
// CHECK-DYNAMIC-BL: store i32 5, i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested3, i64 0, i64 0)
// CHECK-DYNAMIC-BL: store i32 {{.*}}, i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested3, i64 0, i64 1)
// CHECK-DYNAMIC-BL: store i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested3, i64 0, i64 0),
// CHECK-DYNAMIC-BL: store i32 5, i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested2, i64 0, i64 0)
// CHECK-DYNAMIC-BL: store i32 {{.*}}, i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested2, i64 0, i64 1)
// CHECK-DYNAMIC-BL: store i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested2, i64 0, i64 0),
// CHECK-DYNAMIC-BL: i32** getelementptr inbounds ([3 x {{.*}}]* @_ZGR6nested, i64 0, i64 2, i32 0), align 8
// CHECK-DYNAMIC-BL: store i64 2, i64* getelementptr inbounds ([3 x {{.*}}]* @_ZGR6nested, i64 0, i64 2, i32 1), align 8
// CHECK-DYNAMIC-BL: store {{.*}}* getelementptr inbounds ([3 x {{.*}}]* @_ZGR6nested, i64 0, i64 0),
// CHECK-DYNAMIC-BL: {{.*}}** getelementptr inbounds ({{.*}}* @nested, i32 0, i32 0), align 8
// CHECK-DYNAMIC-BL: store i64 3, i64* getelementptr inbounds ({{.*}}* @nested, i32 0, i32 1), align 8
// CHECK-STATIC-BE: @_ZGR6nested = private constant [2 x i32] [i32 1, i32 2], align 4
// CHECK-STATIC-BE: @_ZGR6nested0 = private constant [2 x i32] [i32 1, i32 2], align 4
// CHECK-STATIC-BE: @_ZGR6nested1 = private constant [2 x i32] [i32 3, i32 4], align 4
// CHECK-STATIC-BE: @_ZGR6nested2 = private constant [2 x i32] [i32 5, i32 6], align 4
// CHECK-STATIC-BE: @_ZGR6nested3 = private constant [3 x {{.*}}] [
// CHECK-STATIC-BE: {{.*}} { i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested, i32 0, i32 0),
// CHECK-STATIC-BE: i32* bitcast (i8* getelementptr (i8* bitcast ([2 x i32]* @_ZGR6nested to i8*), i64 8) to i32*) }
// CHECK-STATIC-BE: @_ZGR6nested = private constant [3 x {{.*}}] [
// CHECK-STATIC-BE: {{.*}} { i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested0, i32 0, i32 0),
// CHECK-STATIC-BE: i32* bitcast (i8* getelementptr (i8* bitcast ([2 x i32]* @_ZGR6nested0 to i8*), i64 8) to i32*) }
// CHECK-STATIC-BE: {{.*}} { i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested1, i32 0, i32 0),
// CHECK-STATIC-BE: i32* bitcast (i8* getelementptr (i8* bitcast ([2 x i32]* @_ZGR6nested1 to i8*), i64 8) to i32*) }
// CHECK-STATIC-BE: {{.*}} { i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested2, i32 0, i32 0),
// CHECK-STATIC-BE: i32* bitcast (i8* getelementptr (i8* bitcast ([2 x i32]* @_ZGR6nested2 to i8*), i64 8) to i32*) }
// CHECK-STATIC-BE: ], align 8
// CHECK-STATIC-BE: @nested = global {{.*}} { {{.*}} getelementptr inbounds ([3 x {{.*}}]* @_ZGR6nested3, i32 0, i32 0),
// CHECK-STATIC-BE: {{.*}} bitcast ({{.*}}* getelementptr (i8* bitcast ([3 x {{.*}}]* @_ZGR6nested3 to i8*), i64 48) to {{.*}}*) }
// CHECK-STATIC-BE: @nested = global {{.*}} { {{.*}} getelementptr inbounds ([3 x {{.*}}]* @_ZGR6nested, i32 0, i32 0),
// CHECK-STATIC-BE: {{.*}} bitcast ({{.*}}* getelementptr (i8* bitcast ([3 x {{.*}}]* @_ZGR6nested to i8*), i64 48) to {{.*}}*) }
// CHECK-DYNAMIC-BE: @nested = global
// CHECK-DYNAMIC-BE: @_ZGR6nested = private global [3 x
// CHECK-DYNAMIC-BE: @_ZGR6nested0 = private global [2 x i32] zeroinitializer
// CHECK-DYNAMIC-BE: @_ZGR6nested1 = private global [2 x i32] zeroinitializer
// CHECK-DYNAMIC-BE: @_ZGR6nested2 = private global [2 x i32] zeroinitializer
// CHECK-DYNAMIC-BE: @_ZGR6nested3 = private global [2 x i32] zeroinitializer
// CHECK-DYNAMIC-BE: store i32 1, i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested1, i64 0, i64 0)
// CHECK-DYNAMIC-BE: store i32 1, i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested0, i64 0, i64 0)
// CHECK-DYNAMIC-BE: store i32 {{.*}}, i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested0, i64 0, i64 1)
// CHECK-DYNAMIC-BE: store i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested0, i64 0, i64 0),
// CHECK-DYNAMIC-BE: i32** getelementptr inbounds ([3 x {{.*}}]* @_ZGR6nested, i64 0, i64 0, i32 0), align 8
// CHECK-DYNAMIC-BE: store i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested0, i64 1, i64 0),
// CHECK-DYNAMIC-BE: i32** getelementptr inbounds ([3 x {{.*}}]* @_ZGR6nested, i64 0, i64 0, i32 1), align 8
// CHECK-DYNAMIC-BE: store i32 3, i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested1, i64 0, i64 0)
// CHECK-DYNAMIC-BE: store i32 {{.*}}, i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested1, i64 0, i64 1)
// CHECK-DYNAMIC-BE: store i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested1, i64 0, i64 0),
// CHECK-DYNAMIC-BE: i32** getelementptr inbounds ([3 x {{.*}}]* @_ZGR6nested, i64 0, i64 0, i32 0), align 8
// CHECK-DYNAMIC-BE: i32** getelementptr inbounds ([3 x {{.*}}]* @_ZGR6nested, i64 0, i64 1, i32 0), align 8
// CHECK-DYNAMIC-BE: store i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested1, i64 1, i64 0),
// CHECK-DYNAMIC-BE: i32** getelementptr inbounds ([3 x {{.*}}]* @_ZGR6nested, i64 0, i64 0, i32 1), align 8
// CHECK-DYNAMIC-BE: store i32 3, i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested2, i64 0, i64 0)
// CHECK-DYNAMIC-BE: i32** getelementptr inbounds ([3 x {{.*}}]* @_ZGR6nested, i64 0, i64 1, i32 1), align 8
// CHECK-DYNAMIC-BE: store i32 5, i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested2, i64 0, i64 0)
// CHECK-DYNAMIC-BE: store i32 {{.*}}, i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested2, i64 0, i64 1)
// CHECK-DYNAMIC-BE: store i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested2, i64 0, i64 0),
// CHECK-DYNAMIC-BE: i32** getelementptr inbounds ([3 x {{.*}}]* @_ZGR6nested, i64 0, i64 1, i32 0), align 8
// CHECK-DYNAMIC-BE: store i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested2, i64 1, i64 0),
// CHECK-DYNAMIC-BE: i32** getelementptr inbounds ([3 x {{.*}}]* @_ZGR6nested, i64 0, i64 1, i32 1), align 8
// CHECK-DYNAMIC-BE: store i32 5, i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested3, i64 0, i64 0)
// CHECK-DYNAMIC-BE: store i32 {{.*}}, i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested3, i64 0, i64 1)
// CHECK-DYNAMIC-BE: store i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested3, i64 0, i64 0),
// CHECK-DYNAMIC-BE: i32** getelementptr inbounds ([3 x {{.*}}]* @_ZGR6nested, i64 0, i64 2, i32 0), align 8
// CHECK-DYNAMIC-BE: store i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested3, i64 1, i64 0),
// CHECK-DYNAMIC-BE: store i32* getelementptr inbounds ([2 x i32]* @_ZGR6nested2, i64 1, i64 0),
// CHECK-DYNAMIC-BE: i32** getelementptr inbounds ([3 x {{.*}}]* @_ZGR6nested, i64 0, i64 2, i32 1), align 8
// CHECK-DYNAMIC-BE: store {{.*}}* getelementptr inbounds ([3 x {{.*}}]* @_ZGR6nested, i64 0, i64 0),
// CHECK-DYNAMIC-BE: {{.*}}** getelementptr inbounds ({{.*}}* @nested, i32 0, i32 0), align 8