summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang/include/clang/AST/Expr.h7
-rw-r--r--clang/include/clang/AST/ExprCXX.h39
-rw-r--r--clang/include/clang/AST/RecursiveASTVisitor.h1
-rw-r--r--clang/include/clang/AST/Stmt.h4
-rw-r--r--clang/include/clang/Basic/StmtNodes.td1
-rw-r--r--clang/include/clang/Serialization/ASTBitCodes.h2
-rw-r--r--clang/lib/AST/Expr.cpp2
-rw-r--r--clang/lib/AST/ExprClassification.cpp1
-rw-r--r--clang/lib/AST/ExprConstant.cpp58
-rw-r--r--clang/lib/AST/ItaniumMangle.cpp4
-rw-r--r--clang/lib/AST/StmtPrinter.cpp4
-rw-r--r--clang/lib/AST/StmtProfile.cpp5
-rw-r--r--clang/lib/CodeGen/CGClass.cpp93
-rw-r--r--clang/lib/CodeGen/CGDecl.cpp1
-rw-r--r--clang/lib/CodeGen/CGExpr.cpp9
-rw-r--r--clang/lib/CodeGen/CGExprAgg.cpp190
-rw-r--r--clang/lib/CodeGen/CGExprCXX.cpp2
-rw-r--r--clang/lib/CodeGen/CGExprConstant.cpp5
-rw-r--r--clang/lib/CodeGen/CodeGenFunction.h4
-rw-r--r--clang/lib/CodeGen/CodeGenModule.cpp131
-rw-r--r--clang/lib/CodeGen/CodeGenModule.h2
-rw-r--r--clang/lib/Sema/SemaDeclCXX.cpp9
-rw-r--r--clang/lib/Sema/SemaExceptionSpec.cpp1
-rw-r--r--clang/lib/Sema/SemaInit.cpp209
-rw-r--r--clang/lib/Sema/TreeTransform.h11
-rw-r--r--clang/lib/Serialization/ASTReaderStmt.cpp11
-rw-r--r--clang/lib/Serialization/ASTWriter.cpp1
-rw-r--r--clang/lib/Serialization/ASTWriterStmt.cpp7
-rw-r--r--clang/lib/StaticAnalyzer/Core/ExprEngine.cpp1
-rw-r--r--clang/test/CXX/dcl.decl/dcl.init/dcl.init.list/p3-0x.cpp10
-rw-r--r--clang/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist-pr12086.cpp106
-rw-r--r--clang/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist-startend.cpp4
-rw-r--r--clang/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp82
-rw-r--r--clang/test/SemaCXX/constant-expression-cxx11.cpp41
-rw-r--r--clang/test/SemaCXX/constant-expression-cxx1y.cpp40
-rw-r--r--clang/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp2
-rw-r--r--clang/tools/libclang/CXCursor.cpp1
-rw-r--r--clang/tools/libclang/RecursiveASTVisitor.h1
38 files changed, 601 insertions, 501 deletions
diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h
index ee0a3fd145c..3411e0f8b7f 100644
--- a/clang/include/clang/AST/Expr.h
+++ b/clang/include/clang/AST/Expr.h
@@ -3794,13 +3794,6 @@ public:
InitListExprBits.HadArrayRangeDesignator = ARD;
}
- bool initializesStdInitializerList() const {
- return InitListExprBits.InitializesStdInitializerList != 0;
- }
- void setInitializesStdInitializerList(bool ISIL = true) {
- InitListExprBits.InitializesStdInitializerList = ISIL;
- }
-
SourceLocation getLocStart() const LLVM_READONLY;
SourceLocation getLocEnd() const LLVM_READONLY;
diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h
index 9987587a0b4..2b961d6291d 100644
--- a/clang/include/clang/AST/ExprCXX.h
+++ b/clang/include/clang/AST/ExprCXX.h
@@ -474,6 +474,45 @@ public:
child_range children() { return child_range(); }
};
+/// \brief Implicit construction of a std::initializer_list<T> object from an
+/// array temporary within list-initialization (C++11 [dcl.init.list]p5).
+class CXXStdInitializerListExpr : public Expr {
+ Stmt *SubExpr;
+
+ CXXStdInitializerListExpr(EmptyShell Empty)
+ : Expr(CXXStdInitializerListExprClass, Empty), SubExpr(0) {}
+
+public:
+ CXXStdInitializerListExpr(QualType Ty, Expr *SubExpr)
+ : Expr(CXXStdInitializerListExprClass, Ty, VK_RValue, OK_Ordinary,
+ Ty->isDependentType(), SubExpr->isValueDependent(),
+ SubExpr->isInstantiationDependent(),
+ SubExpr->containsUnexpandedParameterPack()),
+ SubExpr(SubExpr) {}
+
+ Expr *getSubExpr() { return static_cast<Expr*>(SubExpr); }
+ const Expr *getSubExpr() const { return static_cast<const Expr*>(SubExpr); }
+
+ SourceLocation getLocStart() const LLVM_READONLY {
+ return SubExpr->getLocStart();
+ }
+ SourceLocation getLocEnd() const LLVM_READONLY {
+ return SubExpr->getLocEnd();
+ }
+ SourceRange getSourceRange() const LLVM_READONLY {
+ return SubExpr->getSourceRange();
+ }
+
+ static bool classof(const Stmt *S) {
+ return S->getStmtClass() == CXXStdInitializerListExprClass;
+ }
+
+ child_range children() { return child_range(&SubExpr, &SubExpr + 1); }
+
+ friend class ASTReader;
+ friend class ASTStmtReader;
+};
+
/// CXXTypeidExpr - A C++ @c typeid expression (C++ [expr.typeid]), which gets
/// the type_info that corresponds to the supplied type, or the (possibly
/// dynamic) type of the supplied expression.
diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h
index 2c534ac6bc1..1072b97a14a 100644
--- a/clang/include/clang/AST/RecursiveASTVisitor.h
+++ b/clang/include/clang/AST/RecursiveASTVisitor.h
@@ -2177,6 +2177,7 @@ DEF_TRAVERSE_STMT(CXXDefaultInitExpr, { })
DEF_TRAVERSE_STMT(CXXDeleteExpr, { })
DEF_TRAVERSE_STMT(ExprWithCleanups, { })
DEF_TRAVERSE_STMT(CXXNullPtrLiteralExpr, { })
+DEF_TRAVERSE_STMT(CXXStdInitializerListExpr, { })
DEF_TRAVERSE_STMT(CXXPseudoDestructorExpr, {
TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc()));
if (TypeSourceInfo *ScopeInfo = S->getScopeTypeInfo())
diff --git a/clang/include/clang/AST/Stmt.h b/clang/include/clang/AST/Stmt.h
index 882cc2297e2..731a5d0b18b 100644
--- a/clang/include/clang/AST/Stmt.h
+++ b/clang/include/clang/AST/Stmt.h
@@ -266,10 +266,6 @@ protected:
/// Whether this initializer list originally had a GNU array-range
/// designator in it. This is a temporary marker used by CodeGen.
unsigned HadArrayRangeDesignator : 1;
-
- /// Whether this initializer list initializes a std::initializer_list
- /// object.
- unsigned InitializesStdInitializerList : 1;
};
class TypeTraitExprBitfields {
diff --git a/clang/include/clang/Basic/StmtNodes.td b/clang/include/clang/Basic/StmtNodes.td
index cbfce83c4b5..a9c62594051 100644
--- a/clang/include/clang/Basic/StmtNodes.td
+++ b/clang/include/clang/Basic/StmtNodes.td
@@ -110,6 +110,7 @@ def CXXThrowExpr : DStmt<Expr>;
def CXXDefaultArgExpr : DStmt<Expr>;
def CXXDefaultInitExpr : DStmt<Expr>;
def CXXScalarValueInitExpr : DStmt<Expr>;
+def CXXStdInitializerListExpr : DStmt<Expr>;
def CXXNewExpr : DStmt<Expr>;
def CXXDeleteExpr : DStmt<Expr>;
def CXXPseudoDestructorExpr : DStmt<Expr>;
diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h
index 81f89804258..b6ab2d8347e 100644
--- a/clang/include/clang/Serialization/ASTBitCodes.h
+++ b/clang/include/clang/Serialization/ASTBitCodes.h
@@ -1259,6 +1259,8 @@ namespace clang {
EXPR_CXX_FUNCTIONAL_CAST,
/// \brief A UserDefinedLiteral record.
EXPR_USER_DEFINED_LITERAL,
+ /// \brief A CXXStdInitializerListExpr record.
+ EXPR_CXX_STD_INITIALIZER_LIST,
/// \brief A CXXBoolLiteralExpr record.
EXPR_CXX_BOOL_LITERAL,
EXPR_CXX_NULL_PTR_LITERAL, // CXXNullPtrLiteralExpr
diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp
index db4269bf163..ecd147aebe3 100644
--- a/clang/lib/AST/Expr.cpp
+++ b/clang/lib/AST/Expr.cpp
@@ -1789,7 +1789,6 @@ InitListExpr::InitListExpr(ASTContext &C, SourceLocation lbraceloc,
LBraceLoc(lbraceloc), RBraceLoc(rbraceloc), AltForm(0, true)
{
sawArrayRangeDesignator(false);
- setInitializesStdInitializerList(false);
for (unsigned I = 0; I != initExprs.size(); ++I) {
if (initExprs[I]->isTypeDependent())
ExprBits.TypeDependent = true;
@@ -2836,6 +2835,7 @@ bool Expr::HasSideEffects(const ASTContext &Ctx) const {
case DesignatedInitExprClass:
case ParenListExprClass:
case CXXPseudoDestructorExprClass:
+ case CXXStdInitializerListExprClass:
case SubstNonTypeTemplateParmExprClass:
case MaterializeTemporaryExprClass:
case ShuffleVectorExprClass:
diff --git a/clang/lib/AST/ExprClassification.cpp b/clang/lib/AST/ExprClassification.cpp
index bcb6d4e809b..12510d68830 100644
--- a/clang/lib/AST/ExprClassification.cpp
+++ b/clang/lib/AST/ExprClassification.cpp
@@ -353,6 +353,7 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
case Expr::CXXConstructExprClass:
case Expr::CXXTemporaryObjectExprClass:
case Expr::LambdaExprClass:
+ case Expr::CXXStdInitializerListExprClass:
return Cl::CL_ClassTemporary;
case Expr::VAArgExprClass:
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index d94efc13413..21fb4599664 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -4576,6 +4576,7 @@ namespace {
bool VisitCastExpr(const CastExpr *E);
bool VisitInitListExpr(const InitListExpr *E);
bool VisitCXXConstructExpr(const CXXConstructExpr *E);
+ bool VisitCXXStdInitializerListExpr(const CXXStdInitializerListExpr *E);
};
}
@@ -4691,10 +4692,6 @@ bool RecordExprEvaluator::VisitCastExpr(const CastExpr *E) {
}
bool RecordExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
- // Cannot constant-evaluate std::initializer_list inits.
- if (E->initializesStdInitializerList())
- return false;
-
const RecordDecl *RD = E->getType()->castAs<RecordType>()->getDecl();
if (RD->isInvalidDecl()) return false;
const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(RD);
@@ -4810,6 +4807,58 @@ bool RecordExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E) {
Result);
}
+bool RecordExprEvaluator::VisitCXXStdInitializerListExpr(
+ const CXXStdInitializerListExpr *E) {
+ const ConstantArrayType *ArrayType =
+ Info.Ctx.getAsConstantArrayType(E->getSubExpr()->getType());
+
+ LValue Array;
+ if (!EvaluateLValue(E->getSubExpr(), Array, Info))
+ return false;
+
+ // Get a pointer to the first element of the array.
+ Array.addArray(Info, E, ArrayType);
+
+ // FIXME: Perform the checks on the field types in SemaInit.
+ RecordDecl *Record = E->getType()->castAs<RecordType>()->getDecl();
+ RecordDecl::field_iterator Field = Record->field_begin();
+ if (Field == Record->field_end())
+ return Error(E);
+
+ // Start pointer.
+ if (!Field->getType()->isPointerType() ||
+ !Info.Ctx.hasSameType(Field->getType()->getPointeeType(),
+ ArrayType->getElementType()))
+ return Error(E);
+
+ // FIXME: What if the initializer_list type has base classes, etc?
+ Result = APValue(APValue::UninitStruct(), 0, 2);
+ Array.moveInto(Result.getStructField(0));
+
+ if (++Field == Record->field_end())
+ return Error(E);
+
+ if (Field->getType()->isPointerType() &&
+ Info.Ctx.hasSameType(Field->getType()->getPointeeType(),
+ ArrayType->getElementType())) {
+ // End pointer.
+ if (!HandleLValueArrayAdjustment(Info, E, Array,
+ ArrayType->getElementType(),
+ ArrayType->getSize().getZExtValue()))
+ return false;
+ Array.moveInto(Result.getStructField(1));
+ } else if (Info.Ctx.hasSameType(Field->getType(), Info.Ctx.getSizeType()))
+ // Length.
+ Result.getStructField(1) = APValue(APSInt(ArrayType->getSize()));
+ else
+ return Error(E);
+
+ if (++Field != Record->field_end())
+ return Error(E);
+
+ return true;
+}
+
static bool EvaluateRecord(const Expr *E, const LValue &This,
APValue &Result, EvalInfo &Info) {
assert(E->isRValue() && E->getType()->isRecordType() &&
@@ -7762,6 +7811,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
case Expr::UnresolvedLookupExprClass:
case Expr::DependentScopeDeclRefExprClass:
case Expr::CXXConstructExprClass:
+ case Expr::CXXStdInitializerListExprClass:
case Expr::CXXBindTemporaryExprClass:
case Expr::ExprWithCleanupsClass:
case Expr::CXXTemporaryObjectExprClass:
diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp
index 3137f3c8fdc..20f699fafb4 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -2481,6 +2481,10 @@ recurse:
mangleExpression(cast<CXXDefaultInitExpr>(E)->getExpr(), Arity);
break;
+ case Expr::CXXStdInitializerListExprClass:
+ mangleExpression(cast<CXXStdInitializerListExpr>(E)->getSubExpr(), Arity);
+ break;
+
case Expr::SubstNonTypeTemplateParmExprClass:
mangleExpression(cast<SubstNonTypeTemplateParmExpr>(E)->getReplacement(),
Arity);
diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp
index 467413bfb20..d6358023907 100644
--- a/clang/lib/AST/StmtPrinter.cpp
+++ b/clang/lib/AST/StmtPrinter.cpp
@@ -1534,6 +1534,10 @@ void StmtPrinter::VisitCXXConstructExpr(CXXConstructExpr *E) {
OS << " }";
}
+void StmtPrinter::VisitCXXStdInitializerListExpr(CXXStdInitializerListExpr *E) {
+ PrintExpr(E->getSubExpr());
+}
+
void StmtPrinter::VisitExprWithCleanups(ExprWithCleanups *E) {
// Just forward to the sub expression.
PrintExpr(E->getSubExpr());
diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp
index 4a3448c1e5f..391c1e60abe 100644
--- a/clang/lib/AST/StmtProfile.cpp
+++ b/clang/lib/AST/StmtProfile.cpp
@@ -758,6 +758,11 @@ void StmtProfiler::VisitCXXNullPtrLiteralExpr(const CXXNullPtrLiteralExpr *S) {
VisitExpr(S);
}
+void StmtProfiler::VisitCXXStdInitializerListExpr(
+ const CXXStdInitializerListExpr *S) {
+ VisitExpr(S);
+}
+
void StmtProfiler::VisitCXXTypeidExpr(const CXXTypeidExpr *S) {
VisitExpr(S);
if (S->isTypeOperand())
diff --git a/clang/lib/CodeGen/CGClass.cpp b/clang/lib/CodeGen/CGClass.cpp
index b3a14772ad0..9d08d1c7f7a 100644
--- a/clang/lib/CodeGen/CGClass.cpp
+++ b/clang/lib/CodeGen/CGClass.cpp
@@ -433,52 +433,45 @@ static void EmitAggMemberInitializer(CodeGenFunction &CGF,
unsigned Index) {
if (Index == ArrayIndexes.size()) {
LValue LV = LHS;
- { // Scope for Cleanups.
- CodeGenFunction::RunCleanupsScope Cleanups(CGF);
-
- if (ArrayIndexVar) {
- // If we have an array index variable, load it and use it as an offset.
- // Then, increment the value.
- llvm::Value *Dest = LHS.getAddress();
- llvm::Value *ArrayIndex = CGF.Builder.CreateLoad(ArrayIndexVar);
- Dest = CGF.Builder.CreateInBoundsGEP(Dest, ArrayIndex, "destaddress");
- llvm::Value *Next = llvm::ConstantInt::get(ArrayIndex->getType(), 1);
- Next = CGF.Builder.CreateAdd(ArrayIndex, Next, "inc");
- CGF.Builder.CreateStore(Next, ArrayIndexVar);
-
- // Update the LValue.
- LV.setAddress(Dest);
- CharUnits Align = CGF.getContext().getTypeAlignInChars(T);
- LV.setAlignment(std::min(Align, LV.getAlignment()));
- }
- switch (CGF.getEvaluationKind(T)) {
- case TEK_Scalar:
- CGF.EmitScalarInit(Init, /*decl*/ 0, LV, false);
- break;
- case TEK_Complex:
- CGF.EmitComplexExprIntoLValue(Init, LV, /*isInit*/ true);
- break;
- case TEK_Aggregate: {
- AggValueSlot Slot =
- AggValueSlot::forLValue(LV,
- AggValueSlot::IsDestructed,
- AggValueSlot::DoesNotNeedGCBarriers,
- AggValueSlot::IsNotAliased);
-
- CGF.EmitAggExpr(Init, Slot);
- break;
- }
- }
+ if (ArrayIndexVar) {
+ // If we have an array index variable, load it and use it as an offset.
+ // Then, increment the value.
+ llvm::Value *Dest = LHS.getAddress();
+ llvm::Value *ArrayIndex = CGF.Builder.CreateLoad(ArrayIndexVar);
+ Dest = CGF.Builder.CreateInBoundsGEP(Dest, ArrayIndex, "destaddress");
+ llvm::Value *Next = llvm::ConstantInt::get(ArrayIndex->getType(), 1);
+ Next = CGF.Builder.CreateAdd(ArrayIndex, Next, "inc");
+ CGF.Builder.CreateStore(Next, ArrayIndexVar);
+
+ // Update the LValue.
+ LV.setAddress(Dest);
+ CharUnits Align = CGF.getContext().getTypeAlignInChars(T);
+ LV.setAlignment(std::min(Align, LV.getAlignment()));
}
- // Now, outside of the initializer cleanup scope, destroy the backing array
- // for a std::initializer_list member.
- CGF.MaybeEmitStdInitializerListCleanup(LV.getAddress(), Init);
+ switch (CGF.getEvaluationKind(T)) {
+ case TEK_Scalar:
+ CGF.EmitScalarInit(Init, /*decl*/ 0, LV, false);
+ break;
+ case TEK_Complex:
+ CGF.EmitComplexExprIntoLValue(Init, LV, /*isInit*/ true);
+ break;
+ case TEK_Aggregate: {
+ AggValueSlot Slot =
+ AggValueSlot::forLValue(LV,
+ AggValueSlot::IsDestructed,
+ AggValueSlot::DoesNotNeedGCBarriers,
+ AggValueSlot::IsNotAliased);
+
+ CGF.EmitAggExpr(Init, Slot);
+ break;
+ }
+ }
return;
}
-
+
const ConstantArrayType *Array = CGF.getContext().getAsConstantArrayType(T);
assert(Array && "Array initialization without the array type?");
llvm::Value *IndexVar
@@ -512,16 +505,12 @@ static void EmitAggMemberInitializer(CodeGenFunction &CGF,
CGF.EmitBlock(ForBody);
llvm::BasicBlock *ContinueBlock = CGF.createBasicBlock("for.inc");
-
- {
- CodeGenFunction::RunCleanupsScope Cleanups(CGF);
-
- // Inside the loop body recurse to emit the inner loop or, eventually, the
- // constructor call.
- EmitAggMemberInitializer(CGF, LHS, Init, ArrayIndexVar,
- Array->getElementType(), ArrayIndexes, Index + 1);
- }
-
+
+ // Inside the loop body recurse to emit the inner loop or, eventually, the
+ // constructor call.
+ EmitAggMemberInitializer(CGF, LHS, Init, ArrayIndexVar,
+ Array->getElementType(), ArrayIndexes, Index + 1);
+
CGF.EmitBlock(ContinueBlock);
// Emit the increment of the loop counter.
@@ -726,7 +715,7 @@ void CodeGenFunction::EmitConstructorBody(FunctionArgList &Args) {
if (IsTryBody)
EnterCXXTryStmt(*cast<CXXTryStmt>(Body), true);
- EHScopeStack::stable_iterator CleanupDepth = EHStack.stable_begin();
+ RunCleanupsScope RunCleanups(*this);
// TODO: in restricted cases, we can emit the vbase initializers of
// a complete ctor and then delegate to the base ctor.
@@ -745,7 +734,7 @@ void CodeGenFunction::EmitConstructorBody(FunctionArgList &Args) {
// initializers, which includes (along the exceptional path) the
// destructors for those members and bases that were fully
// constructed.
- PopCleanupBlocks(CleanupDepth);
+ RunCleanups.ForceCleanup();
if (IsTryBody)
ExitCXXTryStmt(*cast<CXXTryStmt>(Body), true);
diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp
index 7fc79e08f0f..4d14014f9c9 100644
--- a/clang/lib/CodeGen/CGDecl.cpp
+++ b/clang/lib/CodeGen/CGDecl.cpp
@@ -1187,7 +1187,6 @@ void CodeGenFunction::EmitExprAsInit(const Expr *init,
AggValueSlot::DoesNotNeedGCBarriers,
AggValueSlot::IsNotAliased));
}
- MaybeEmitStdInitializerListCleanup(lvalue.getAddress(), init);
return;
}
llvm_unreachable("bad evaluation kind");
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index d534ff440cf..f88da33fbf5 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -240,15 +240,6 @@ pushTemporaryCleanup(CodeGenFunction &CGF, const MaterializeTemporaryExpr *M,
}
}
- if (const InitListExpr *ILE = dyn_cast<InitListExpr>(E)) {
- if (ILE->initializesStdInitializerList()) {
- // FIXME: This is wrong if the temporary has static or thread storage
- // duration.
- CGF.EmitStdInitializerListCleanup(ReferenceTemporary, ILE);
- return;
- }
- }
-
CXXDestructorDecl *ReferenceTemporaryDtor = 0;
if (const RecordType *RT =
E->getType()->getBaseElementTypeUnsafe()->getAs<RecordType>()) {
diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp
index f8b19d686b2..f3eb34567bd 100644
--- a/clang/lib/CodeGen/CGExprAgg.cpp
+++ b/clang/lib/CodeGen/CGExprAgg.cpp
@@ -91,7 +91,6 @@ public:
void EmitMoveFromReturnSlot(const Expr *E, RValue Src);
- void EmitStdInitializerList(llvm::Value *DestPtr, InitListExpr *InitList);
void EmitArrayInit(llvm::Value *DestPtr, llvm::ArrayType *AType,
QualType elementType, InitListExpr *E);
@@ -177,6 +176,7 @@ public:
void VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E);
void VisitCXXConstructExpr(const CXXConstructExpr *E);
void VisitLambdaExpr(LambdaExpr *E);
+ void VisitCXXStdInitializerListExpr(CXXStdInitializerListExpr *E);
void VisitExprWithCleanups(ExprWithCleanups *E);
void VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *E);
void VisitCXXTypeidExpr(CXXTypeidExpr *E) { EmitAggLoadOfLValue(E); }
@@ -345,89 +345,70 @@ void AggExprEmitter::EmitCopy(QualType type, const AggValueSlot &dest,
std::min(dest.getAlignment(), src.getAlignment()));
}
-static QualType GetStdInitializerListElementType(QualType T) {
- // Just assume that this is really std::initializer_list.
- ClassTemplateSpecializationDecl *specialization =
- cast<ClassTemplateSpecializationDecl>(T->castAs<RecordType>()->getDecl());
- return specialization->getTemplateArgs()[0].getAsType();
-}
-
-/// \brief Prepare cleanup for the temporary array.
-static void EmitStdInitializerListCleanup(CodeGenFunction &CGF,
- QualType arrayType,
- llvm::Value *addr,
- const InitListExpr *initList) {
- QualType::DestructionKind dtorKind = arrayType.isDestructedType();
- if (!dtorKind)
- return; // Type doesn't need destroying.
- if (dtorKind != QualType::DK_cxx_destructor) {
- CGF.ErrorUnsupported(initList, "ObjC ARC type in initializer_list");
- return;
- }
-
- CodeGenFunction::Destroyer *destroyer = CGF.getDestroyer(dtorKind);
- CGF.pushDestroy(NormalAndEHCleanup, addr, arrayType, destroyer,
- /*EHCleanup=*/true);
-}
-
/// \brief Emit the initializer for a std::initializer_list initialized with a
/// real initializer list.
-void AggExprEmitter::EmitStdInitializerList(llvm::Value *destPtr,
- InitListExpr *initList) {
- // We emit an array containing the elements, then have the init list point
- // at the array.
- ASTContext &ctx = CGF.getContext();
- unsigned numInits = initList->getNumInits();
- QualType element = GetStdInitializerListElementType(initList->getType());
- llvm::APInt size(ctx.getTypeSize(ctx.getSizeType()), numInits);
- QualType array = ctx.getConstantArrayType(element, size, ArrayType::Normal,0);
- llvm::Type *LTy = CGF.ConvertTypeForMem(array);
- llvm::AllocaInst *alloc = CGF.CreateTempAlloca(LTy);
- alloc->setAlignment(ctx.getTypeAlignInChars(array).getQuantity());
- alloc->setName(".initlist.");
-
- EmitArrayInit(alloc, cast<llvm::ArrayType>(LTy), element, initList);
-
- // FIXME: The diagnostics are somewhat out of place here.
- RecordDecl *record = initList->getType()->castAs<RecordType>()->getDecl();
- RecordDecl::field_iterator field = record->field_begin();
- if (field == record->field_end()) {
- CGF.ErrorUnsupported(initList, "weird std::initializer_list");
+void
+AggExprEmitter::VisitCXXStdInitializerListExpr(CXXStdInitializerListExpr *E) {
+ // Emit an array containing the elements. The array is externally destructed
+ // if the std::initializer_list object is.
+ ASTContext &Ctx = CGF.getContext();
+ LValue Array = CGF.EmitLValue(E->getSubExpr());
+ assert(Array.isSimple() && "initializer_list array not a simple lvalue");
+ llvm::Value *ArrayPtr = Array.getAddress();
+
+ const ConstantArrayType *ArrayType =
+ Ctx.getAsConstantArrayType(E->getSubExpr()->getType());
+ assert(ArrayType && "std::initializer_list constructed from non-array");
+
+ // FIXME: Perform the checks on the field types in SemaInit.
+ RecordDecl *Record = E->getType()->castAs<RecordType>()->getDecl();
+ RecordDecl::field_iterator Field = Record->field_begin();
+ if (Field == Record->field_end()) {
+ CGF.ErrorUnsupported(E, "weird std::initializer_list");
return;
}
- QualType elementPtr = ctx.getPointerType(element.withConst());
-
// Start pointer.
- if (!ctx.hasSameType(field->getType(), elementPtr)) {
- CGF.ErrorUnsupported(initList, "weird std::initializer_list");
+ if (!Field->getType()->isPointerType() ||
+ !Ctx.hasSameType(Field->getType()->getPointeeType(),
+ ArrayType->getElementType())) {
+ CGF.ErrorUnsupported(E, "weird std::initializer_list");
return;
}
- LValue DestLV = CGF.MakeNaturalAlignAddrLValue(destPtr, initList->getType());
- LValue start = CGF.EmitLValueForFieldInitialization(DestLV, *field);
- llvm::Value *arrayStart = Builder.CreateStructGEP(alloc, 0, "arraystart");
- CGF.EmitStoreThroughLValue(RValue::get(arrayStart), start);
- ++field;
-
- if (field == record->field_end()) {
- CGF.ErrorUnsupported(initList, "weird std::initializer_list");
+
+ AggValueSlot Dest = EnsureSlot(E->getType());
+ LValue DestLV = CGF.MakeAddrLValue(Dest.getAddr(), E->getType(),
+ Dest.getAlignment());
+ LValue Start = CGF.EmitLValueForFieldInitialization(DestLV, *Field);
+ llvm::Value *Zero = llvm::ConstantInt::get(CGF.PtrDiffTy, 0);
+ llvm::Value *IdxStart[] = { Zero, Zero };
+ llvm::Value *ArrayStart =
+ Builder.CreateInBoundsGEP(ArrayPtr, IdxStart, "arraystart");
+ CGF.EmitStoreThroughLValue(RValue::get(ArrayStart), Start);
+ ++Field;
+
+ if (Field == Record->field_end()) {
+ CGF.ErrorUnsupported(E, "weird std::initializer_list");
return;
}
- LValue endOrLength = CGF.EmitLValueForFieldInitialization(DestLV, *field);
- if (ctx.hasSameType(field->getType(), elementPtr)) {
+
+ llvm::Value *Size = Builder.getInt(ArrayType->getSize());
+ LValue EndOrLength = CGF.EmitLValueForFieldInitialization(DestLV, *Field);
+ if (Field->getType()->isPointerType() &&
+ Ctx.hasSameType(Field->getType()->getPointeeType(),
+ ArrayType->getElementType())) {
// End pointer.
- llvm::Value *arrayEnd = Builder.CreateStructGEP(alloc,numInits, "arrayend");
- CGF.EmitStoreThroughLValue(RValue::get(arrayEnd), endOrLength);
- } else if(ctx.hasSameType(field->getType(), ctx.getSizeType())) {
+ llvm::Value *IdxEnd[] = { Zero, Size };
+ llvm::Value *ArrayEnd =
+ Builder.CreateInBoundsGEP(ArrayPtr, IdxEnd, "arrayend");
+ CGF.EmitStoreThroughLValue(RValue::get(ArrayEnd), EndOrLength);
+ } else if (Ctx.hasSameType(Field->getType(), Ctx.getSizeType())) {
// Length.
- CGF.EmitStoreThroughLValue(RValue::get(Builder.getInt(size)), endOrLength);
+ CGF.EmitStoreThroughLValue(RValue::get(Size), EndOrLength);
} else {
- CGF.ErrorUnsupported(initList, "weird std::initializer_list");
+ CGF.ErrorUnsupported(E, "weird std::initializer_list");
return;
}
-
- if (!Dest.isExternallyDestructed())
- EmitStdInitializerListCleanup(CGF, array, alloc, initList);
}
/// \brief Emit initialization of an array from an initializer list.
@@ -490,15 +471,8 @@ void AggExprEmitter::EmitArrayInit(llvm::Value *DestPtr, llvm::ArrayType *AType,
if (endOfInit) Builder.CreateStore(element, endOfInit);
}
- // If these are nested std::initializer_list inits, do them directly,
- // because they are conceptually the same "location".
- InitListExpr *initList = dyn_cast<InitListExpr>(E->getInit(i));
- if (initList && initList->initializesStdInitializerList()) {
- EmitStdInitializerList(element, initList);
- } else {
- LValue elementLV = CGF.MakeAddrLValue(element, elementType);
- EmitInitializationToLValue(E->getInit(i), elementLV);
- }
+ LValue elementLV = CGF.MakeAddrLValue(element, elementType);
+ EmitInitializationToLValue(E->getInit(i), elementLV);
}
// Check whether there's a non-trivial array-fill expression.
@@ -1161,11 +1135,6 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) {
AggValueSlot Dest = EnsureSlot(E->getType());
- if (E->initializesStdInitializerList()) {
- EmitStdInitializerList(Dest.getAddr(), E);
- return;
- }
-
LValue DestLV = CGF.MakeAddrLValue(Dest.getAddr(), E->getType(),
Dest.getAlignment());
@@ -1546,58 +1515,3 @@ void CodeGenFunction::EmitAggregateCopy(llvm::Value *DestPtr,
alignment.getQuantity(), isVolatile,
/*TBAATag=*/0, TBAAStructTag);
}
-
-void CodeGenFunction::MaybeEmitStdInitializerListCleanup(llvm::Value *loc,
- const Expr *init) {
- const ExprWithCleanups *cleanups = dyn_cast<ExprWithCleanups>(init);
- if (cleanups)
- init = cleanups->getSubExpr();
-
- if (isa<InitListExpr>(init) &&
- cast<InitListExpr>(init)->initializesStdInitializerList()) {
- // We initialized this std::initializer_list with an initializer list.
- // A backing array was created. Push a cleanup for it.
- EmitStdInitializerListCleanup(loc, cast<InitListExpr>(init));
- }
-}
-
-static void EmitRecursiveStdInitializerListCleanup(CodeGenFunction &CGF,
- llvm::Value *arrayStart,
- const InitListExpr *init) {
- // Check if there are any recursive cleanups to do, i.e. if we have
- // std::initializer_list<std::initializer_list<obj>> list = {{obj()}};
- // then we need to destroy the inner array as well.
- for (unsigned i = 0, e = init->getNumInits(); i != e; ++i) {
- const InitListExpr *subInit = dyn_cast<InitListExpr>(init->getInit(i));
- if (!subInit || !subInit->initializesStdInitializerList())
- continue;
-
- // This one needs to be destroyed. Get the address of the std::init_list.
- llvm::Value *offset = llvm::ConstantInt::get(CGF.SizeTy, i);
- llvm::Value *loc = CGF.Builder.CreateInBoundsGEP(arrayStart, offset,
- "std.initlist");
- CGF.EmitStdInitializerListCleanup(loc, subInit);
- }
-}
-
-void CodeGenFunction::EmitStdInitializerListCleanup(llvm::Value *loc,
- const InitListExpr *init) {
- ASTContext &ctx = getContext();
- QualType element = GetStdInitializerListElementType(init->getType());
- unsigned numInits = init->getNumInits();
- llvm::APInt size(ctx.getTypeSize(ctx.getSizeType()), numInits);
- QualType array =ctx.getConstantArrayType(element, size, ArrayType::Normal, 0);
- QualType arrayPtr = ctx.getPointerType(array);
- llvm::Type *arrayPtrType = ConvertType(arrayPtr);
-
- // lvalue is the location of a std::initializer_list, which as its first
- // element has a pointer to the array we want to destroy.
- llvm::Value *startPointer = Builder.CreateStructGEP(loc, 0, "startPointer");
- llvm::Value *startAddress = Builder.CreateLoad(startPointer, "startAddress");
-
- ::EmitRecursiveStdInitializerListCleanup(*this, startAddress, init);
-
- llvm::Value *arrayAddress =
- Builder.CreateBitCast(startAddress, arrayPtrType, "arrayAddress");
- ::EmitStdInitializerListCleanup(*this, array, arrayAddress, init);
-}
diff --git a/clang/lib/CodeGen/CGExprCXX.cpp b/clang/lib/CodeGen/CGExprCXX.cpp
index 83c8ace98cd..60a70f8e07f 100644
--- a/clang/lib/CodeGen/CGExprCXX.cpp
+++ b/clang/lib/CodeGen/CGExprCXX.cpp
@@ -838,8 +838,6 @@ static void StoreAnyExprIntoOneUnit(CodeGenFunction &CGF, const Expr *Init,
AggValueSlot::DoesNotNeedGCBarriers,
AggValueSlot::IsNotAliased);
CGF.EmitAggExpr(Init, Slot);
-
- CGF.MaybeEmitStdInitializerListCleanup(NewPtr, Init);
return;
}
}
diff --git a/clang/lib/CodeGen/CGExprConstant.cpp b/clang/lib/CodeGen/CGExprConstant.cpp
index ca331cc92be..3e13e972801 100644
--- a/clang/lib/CodeGen/CGExprConstant.cpp
+++ b/clang/lib/CodeGen/CGExprConstant.cpp
@@ -368,11 +368,6 @@ void ConstStructBuilder::ConvertStructToPacked() {
}
bool ConstStructBuilder::Build(InitListExpr *ILE) {
- if (ILE->initializesStdInitializerList()) {
- //CGM.ErrorUnsupported(ILE, "global std::initializer_list");
- return false;
- }
-
RecordDecl *RD = ILE->getType()->getAs<RecordType>()->getDecl();
const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h
index 7bbf788eb52..4619322e1e1 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -1631,10 +1631,6 @@ public:
llvm::Value *EmitDynamicCast(llvm::Value *V, const CXXDynamicCastExpr *DCE);
llvm::Value* EmitCXXUuidofExpr(const CXXUuidofExpr *E);
- void MaybeEmitStdInitializerListCleanup(llvm::Value *loc, const Expr *init);
- void EmitStdInitializerListCleanup(llvm::Value *loc,
- const InitListExpr *init);
-
/// \brief Situations in which we might emit a check for the suitability of a
/// pointer or glvalue.
enum TypeCheckKind {
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index d49fc0b0315..f6218cddfb5 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -1628,125 +1628,6 @@ CharUnits CodeGenModule::GetTargetTypeStoreSize(llvm::Type *Ty) const {
TheDataLayout.getTypeStoreSizeInBits(Ty));
}
-llvm::Constant *
-CodeGenModule::MaybeEmitGlobalStdInitializerListInitializer(const VarDecl *D,
- const Expr *rawInit) {
- ArrayRef<ExprWithCleanups::CleanupObject> cleanups;
- if (const ExprWithCleanups *withCleanups =
- dyn_cast<ExprWithCleanups>(rawInit)) {
- cleanups = withCleanups->getObjects();
- rawInit = withCleanups->getSubExpr();
- }
-
- const InitListExpr *init = dyn_cast<InitListExpr>(rawInit);
- if (!init || !init->initializesStdInitializerList() ||
- init->getNumInits() == 0)
- return 0;
-
- ASTContext &ctx = getContext();
- unsigned numInits = init->getNumInits();
- // FIXME: This check is here because we would otherwise silently miscompile
- // nested global std::initializer_lists. Better would be to have a real
- // implementation.
- for (unsigned i = 0; i < numInits; ++i) {
- const InitListExpr *inner = dyn_cast<InitListExpr>(init->getInit(i));
- if (inner && inner->initializesStdInitializerList()) {
- ErrorUnsupported(inner, "nested global std::initializer_list");
- return 0;
- }
- }
-
- // Synthesize a fake VarDecl for the array and initialize that.
- QualType elementType = init->getInit(0)->getType();
- llvm::APInt numElements(ctx.getTypeSize(ctx.getSizeType()), numInits);
- QualType arrayType = ctx.getConstantArrayType(elementType, numElements,
- ArrayType::Normal, 0);
-
- IdentifierInfo *name = &ctx.Idents.get(D->getNameAsString() + "__initlist");
- TypeSourceInfo *sourceInfo = ctx.getTrivialTypeSourceInfo(
- arrayType, D->getLocation());
- VarDecl *backingArray = VarDecl::Create(ctx, const_cast<DeclContext*>(
- D->getDeclContext()),
- D->getLocStart(), D->getLocation(),
- name, arrayType, sourceInfo,
- SC_Static);
- backingArray->setTSCSpec(D->getTSCSpec());
-
- // Now clone the InitListExpr to initialize the array instead.
- // Incredible hack: we want to use the existing InitListExpr here, so we need
- // to tell it that it no longer initializes a std::initializer_list.
- ArrayRef<Expr*> Inits(const_cast<InitListExpr*>(init)->getInits(),
- init->getNumInits());
- Expr *arrayInit = new (ctx) InitListExpr(ctx, init->getLBraceLoc(), Inits,
- init->getRBraceLoc());
- arrayInit->setType(arrayType);
-
- if (!cleanups.empty())
- arrayInit = ExprWithCleanups::Create(ctx, arrayInit, cleanups);
-
- backingArray->setInit(arrayInit);
-
- // Emit the definition of the array.
- EmitGlobalVarDefinition(backingArray);
-
- // Inspect the initializer list to validate it and determine its type.
- // FIXME: doing this every time is probably inefficient; caching would be nice
- RecordDecl *record = init->getType()->castAs<RecordType>()->getDecl();
- RecordDecl::field_iterator field = record->field_begin();
- if (field == record->field_end()) {
- ErrorUnsupported(D, "weird std::initializer_list");
- return 0;
- }
- QualType elementPtr = ctx.getPointerType(elementType.withConst());
- // Start pointer.
- if (!ctx.hasSameType(field->getType(), elementPtr)) {
- ErrorUnsupported(D, "weird std::initializer_list");
- return 0;
- }
- ++field;
- if (field == record->field_end()) {
- ErrorUnsupported(D, "weird std::initializer_list");
- return 0;
- }
- bool isStartEnd = false;
- if (ctx.hasSameType(field->getType(), elementPtr)) {
- // End pointer.
- isStartEnd = true;
- } else if(!ctx.hasSameType(field->getType(), ctx.getSizeType())) {
- ErrorUnsupported(D, "weird std::initializer_list");
- return 0;
- }
-
- // Now build an APValue representing the std::initializer_list.
- APValue initListValue(APValue::UninitStruct(), 0, 2);
- APValue &startField = initListValue.getStructField(0);
- APValue::LValuePathEntry startOffsetPathEntry;
- startOffsetPathEntry.ArrayIndex = 0;
- startField = APValue(APValue::LValueBase(backingArray),
- CharUnits::fromQuantity(0),
- llvm::makeArrayRef(startOffsetPathEntry),
- /*IsOnePastTheEnd=*/false, 0);
-
- if (isStartEnd) {
- APValue &endField = initListValue.getStructField(1);
- APValue::LValuePathEntry endOffsetPathEntry;
- endOffsetPathEntry.ArrayIndex = numInits;
- endField = APValue(APValue::LValueBase(backingArray),
- ctx.getTypeSizeInChars(elementType) * numInits,
- llvm::makeArrayRef(endOffsetPathEntry),
- /*IsOnePastTheEnd=*/true, 0);
- } else {
- APValue &sizeField = initListValue.getStructField(1);
- sizeField = APValue(llvm::APSInt(numElements));
- }
-
- // Emit the constant for the initializer_list.
- llvm::Constant *llvmInit =
- EmitConstantValueForMemory(initListValue, D->getType());
- assert(llvmInit && "failed to initialize as constant");
- return llvmInit;
-}
-
unsigned CodeGenModule::GetGlobalVarAddressSpace(const VarDecl *D,
unsigned AddrSpace) {
if (LangOpts.CUDA && CodeGenOpts.CUDAIsDevice) {
@@ -1817,18 +1698,10 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) {
assert(!ASTTy->isIncompleteType() && "Unexpected incomplete type");
Init = EmitNullConstant(D->getType());
} else {
- // If this is a std::initializer_list, emit the special initializer.
- Init = MaybeEmitGlobalStdInitializerListInitializer(D, InitExpr);
- // An empty init list will perform zero-initialization, which happens
- // to be exactly what we want.
- // FIXME: It does so in a global constructor, which is *not* what we
- // want.
+ initializedGlobalDecl = GlobalDecl(D);
+ Init = EmitConstantInit(*InitDecl);
if (!Init) {
- initializedGlobalDecl = GlobalDecl(D);
- Init = EmitConstantInit(*InitDecl);
- }
- if (!Init) {
QualType T = InitExpr->getType();
if (D->getType()->isReferenceType())
T = D->getType();
diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h
index b2ff60deff2..ffb1243726e 100644
--- a/clang/lib/CodeGen/CodeGenModule.h
+++ b/clang/lib/CodeGen/CodeGenModule.h
@@ -1020,8 +1020,6 @@ private:
void EmitGlobalFunctionDefinition(GlobalDecl GD);
void EmitGlobalVarDefinition(const VarDecl *D);
- llvm::Constant *MaybeEmitGlobalStdInitializerListInitializer(const VarDecl *D,
- const Expr *init);
void EmitAliasDefinition(GlobalDecl GD);
void EmitObjCPropertyImplementations(const ObjCImplementationDecl *D);
void EmitObjCIvarInitializations(ObjCImplementationDecl *D);
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 5d6eab0f173..be198ad3782 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -2153,10 +2153,6 @@ Sema::ActOnCXXInClassMemberInitializer(Decl *D, SourceLocation InitLoc,
ExprResult Init = InitExpr;
if (!FD->getType()->isDependentType() && !InitExpr->isTypeDependent()) {
- if (isa<InitListExpr>(InitExpr) && isStdInitializerList(FD->getType(), 0)) {
- Diag(FD->getLocation(), diag::warn_dangling_std_initializer_list)
- << /*at end of ctor*/1 << InitExpr->getSourceRange();
- }
InitializedEntity Entity = InitializedEntity::InitializeMember(FD);
InitializationKind Kind = FD->getInClassInitStyle() == ICIS_ListInit
? InitializationKind::CreateDirectList(InitExpr->getLocStart())
@@ -2550,11 +2546,6 @@ Sema::BuildMemberInitializer(ValueDecl *Member, Expr *Init,
if (isa<InitListExpr>(Init)) {
InitList = true;
Args = Init;
-
- if (isStdInitializerList(Member->getType(), 0)) {
- Diag(IdLoc, diag::warn_dangling_std_initializer_list)
- << /*at end of ctor*/1 << InitRange;
- }
}
// Initialize the member.
diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp
index a121a75fa48..7ed32b89e3d 100644
--- a/clang/lib/Sema/SemaExceptionSpec.cpp
+++ b/clang/lib/Sema/SemaExceptionSpec.cpp
@@ -1006,6 +1006,7 @@ CanThrowResult Sema::canThrow(const Expr *E) {
case Expr::CompoundLiteralExprClass:
case Expr::CXXConstCastExprClass:
case Expr::CXXReinterpretCastExprClass:
+ case Expr::CXXStdInitializerListExprClass:
case Expr::DesignatedInitExprClass:
case Expr::ExprWithCleanupsClass:
case Expr::ExtVectorElementExprClass:
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index a4bccacb2da..18b3d8225e0 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -2937,6 +2937,12 @@ static void MaybeProduceObjCObject(Sema &S,
}
}
+static void TryListInitialization(Sema &S,
+ const InitializedEntity &Entity,
+ const InitializationKind &Kind,
+ InitListExpr *InitList,
+ InitializationSequence &Sequence);
+
/// \brief When initializing from init list via constructor, handle
/// initialization of an object of type std::initializer_list<T>.
///
@@ -2950,25 +2956,23 @@ static bool TryInitializerListConstruction(Sema &S,
if (!S.isStdInitializerList(DestType, &E))
return false;
- // Check that each individual element can be copy-constructed. But since we
- // have no place to store further information, we'll recalculate everything
- // later.
- InitializedEntity HiddenArray = InitializedEntity::InitializeTemporary(
- S.Context.getConstantArrayType(E,
- llvm::APInt(S.Context.getTypeSize(S.Context.getSizeType()),
- List->getNumInits()),
- ArrayType::Normal, 0));
- InitializedEntity Element = InitializedEntity::InitializeElement(S.Context,
- 0, HiddenArray);
- for (unsigned i = 0, n = List->getNumInits(); i < n; ++i) {
- Element.setElementIndex(i);
- if (!S.CanPerformCopyInitialization(Element, List->getInit(i))) {
- Sequence.SetFailed(
- InitializationSequence::FK_InitListElementCopyFailure);
- return true;
- }
+ if (S.RequireCompleteType(List->getExprLoc(), E, 0)) {
+ Sequence.setIncompleteTypeFailure(E);
+ return true;
}
- Sequence.AddStdInitializerListConstructionStep(DestType);
+
+ // Try initializing a temporary array from the init list.
+ QualType ArrayType = S.Context.getConstantArrayType(
+ E.withConst(), llvm::APInt(S.Context.getTypeSize(S.Context.getSizeType()),
+ List->getNumInits()),
+ clang::ArrayType::Normal, 0);
+ InitializedEntity HiddenArray =
+ InitializedEntity::InitializeTemporary(ArrayType);
+ InitializationKind Kind =
+ InitializationKind::CreateDirectList(List->getExprLoc());
+ TryListInitialization(S, HiddenArray, Kind, List, Sequence);
+ if (Sequence)
+ Sequence.AddStdInitializerListConstructionStep(DestType);
return true;
}
@@ -3198,12 +3202,6 @@ static void TryValueInitialization(Sema &S,
InitializationSequence &Sequence,
InitListExpr *InitList = 0);
-static void TryListInitialization(Sema &S,
- const InitializedEntity &Entity,
- const InitializationKind &Kind,
- InitListExpr *InitList,
- InitializationSequence &Sequence);
-
/// \brief Attempt list initialization of a reference.
static void TryReferenceListInitialization(Sema &S,
const InitializedEntity &Entity,
@@ -5135,7 +5133,7 @@ PerformConstructorInitialization(Sema &S,
return ExprError();
if (shouldBindAsTemporary(Entity))
- CurInit = S.MaybeBindToTemporary(CurInit.takeAs<Expr>());
+ CurInit = S.MaybeBindToTemporary(CurInit.take());
return CurInit;
}
@@ -5277,19 +5275,18 @@ static void performLifetimeExtension(Expr *Init, const ValueDecl *ExtendingD) {
if (CXXBindTemporaryExpr *BTE = dyn_cast<CXXBindTemporaryExpr>(Init))
Init = BTE->getSubExpr();
+ if (CXXStdInitializerListExpr *ILE =
+ dyn_cast<CXXStdInitializerListExpr>(Init))
+ return performReferenceExtension(ILE->getSubExpr(), ExtendingD);
+
if (InitListExpr *ILE = dyn_cast<InitListExpr>(Init)) {
- if (ILE->initializesStdInitializerList() || ILE->getType()->isArrayType()) {
- // FIXME: If this is an InitListExpr which creates a std::initializer_list
- // object, we also need to lifetime-extend the underlying array
- // itself. Fix the representation to explicitly materialize an
- // array temporary so we can model this properly.
+ if (ILE->getType()->isArrayType()) {
for (unsigned I = 0, N = ILE->getNumInits(); I != N; ++I)
performLifetimeExtension(ILE->getInit(I), ExtendingD);
return;
}
- CXXRecordDecl *RD = ILE->getType()->getAsCXXRecordDecl();
- if (RD) {
+ if (CXXRecordDecl *RD = ILE->getType()->getAsCXXRecordDecl()) {
assert(RD->isAggregate() && "aggregate init on non-aggregate");
// If we lifetime-extend a braced initializer which is initializing an
@@ -5319,6 +5316,39 @@ static void performLifetimeExtension(Expr *Init, const ValueDecl *ExtendingD) {
}
}
+static void warnOnLifetimeExtension(Sema &S, const InitializedEntity &Entity,
+ const Expr *Init, bool IsInitializerList,
+ const ValueDecl *ExtendingDecl) {
+ // Warn if a field lifetime-extends a temporary.
+ if (isa<FieldDecl>(ExtendingDecl)) {
+ if (IsInitializerList) {
+ S.Diag(Init->getExprLoc(), diag::warn_dangling_std_initializer_list)
+ << /*at end of constructor*/true;
+ return;
+ }
+
+ bool IsSubobjectMember = false;
+ for (const InitializedEntity *Ent = Entity.getParent(); Ent;
+ Ent = Ent->getParent()) {
+ if (Ent->getKind() != InitializedEntity::EK_Base) {
+ IsSubobjectMember = true;
+ break;
+ }
+ }
+ S.Diag(Init->getExprLoc(),
+ diag::warn_bind_ref_member_to_temporary)
+ << ExtendingDecl << Init->getSourceRange()
+ << IsSubobjectMember << IsInitializerList;
+ if (IsSubobjectMember)
+ S.Diag(ExtendingDecl->getLocation(),
+ diag::note_ref_subobject_of_member_declared_here);
+ else
+ S.Diag(ExtendingDecl->getLocation(),
+ diag::note_ref_or_ptr_member_declared_here)
+ << /*is pointer*/false;
+ }
+}
+
ExprResult
InitializationSequence::Perform(Sema &S,
const InitializedEntity &Entity,
@@ -5570,29 +5600,7 @@ InitializationSequence::Perform(Sema &S,
getDeclForTemporaryLifetimeExtension(Entity);
if (ExtendingDecl) {
performLifetimeExtension(CurInit.get(), ExtendingDecl);
-
- // Warn if a field lifetime-extends a temporary.
- if (isa<FieldDecl>(ExtendingDecl)) {
- bool IsSubobjectMember = false;
- for (const InitializedEntity *Ent = Entity.getParent(); Ent;
- Ent = Ent->getParent()) {
- if (Ent->getKind() != InitializedEntity::EK_Base) {
- IsSubobjectMember = true;
- break;
- }
- }
- S.Diag(CurInit.get()->getExprLoc(),
- diag::warn_bind_ref_member_to_temporary)
- << ExtendingDecl << CurInit.get()->getSourceRange()
- << IsSubobjectMember;
- if (IsSubobjectMember)
- S.Diag(ExtendingDecl->getLocation(),
- diag::note_ref_subobject_of_member_declared_here);
- else
- S.Diag(ExtendingDecl->getLocation(),
- diag::note_ref_or_ptr_member_declared_here)
- << /*IsPointer*/false;
- }
+ warnOnLifetimeExtension(S, Entity, CurInit.get(), false, ExtendingDecl);
}
// Materialize the temporary into memory.
@@ -5763,16 +5771,10 @@ InitializationSequence::Perform(Sema &S,
case SK_ListInitialization: {
InitListExpr *InitList = cast<InitListExpr>(CurInit.get());
- // Hack: We must pass *ResultType if available in order to set the type
- // of arrays, e.g. in 'int ar[] = {1, 2, 3};'.
- // But in 'const X &x = {1, 2, 3};' we're supposed to initialize a
- // temporary, not a reference, so we should pass Ty.
- // Worst case: 'const int (&arref)[] = {1, 2, 3};'.
- // Since this step is never used for a reference directly, we explicitly
- // unwrap references here and rewrap them afterwards.
- // We also need to create a InitializeTemporary entity for this.
- QualType Ty = ResultType ? ResultType->getNonReferenceType() : Step->Type;
- bool IsTemporary = Entity.getType()->isReferenceType();
+ // If we're not initializing the top-level entity, we need to create an
+ // InitializeTemporary entity for our target type.
+ QualType Ty = Step->Type;
+ bool IsTemporary = !S.Context.hasSameType(Entity.getType(), Ty);
InitializedEntity TempEntity = InitializedEntity::InitializeTemporary(Ty);
InitializedEntity InitEntity = IsTemporary ? TempEntity : Entity;
InitListChecker PerformInitList(S, InitEntity,
@@ -5780,7 +5782,11 @@ InitializationSequence::Perform(Sema &S,
if (PerformInitList.HadError())
return ExprError();
- if (ResultType) {
+ // Hack: We must update *ResultType if available in order to set the
+ // bounds of arrays, e.g. in 'int ar[] = {1, 2, 3};'.
+ // Worst case: 'const int (&arref)[] = {1, 2, 3};'.
+ if (ResultType &&
+ ResultType->getNonReferenceType()->isIncompleteArrayType()) {
if ((*ResultType)->isRValueReferenceType())
Ty = S.Context.getRValueReferenceType(Ty);
else if ((*ResultType)->isLValueReferenceType())
@@ -5973,56 +5979,35 @@ InitializationSequence::Perform(Sema &S,
break;
case SK_StdInitializerList: {
- QualType Dest = Step->Type;
- QualType E;
- bool Success = S.isStdInitializerList(Dest.getNonReferenceType(), &E);
- (void)Success;
- assert(Success && "Destination type changed?");
-
- // If the element type has a destructor, check it.
- if (CXXRecordDecl *RD = E->getAsCXXRecordDecl()) {
- if (!RD->hasIrrelevantDestructor()) {
- if (CXXDestructorDecl *Destructor = S.LookupDestructor(RD)) {
- S.MarkFunctionReferenced(Kind.getLocation(), Destructor);
- S.CheckDestructorAccess(Kind.getLocation(), Destructor,
- S.PDiag(diag::err_access_dtor_temp) << E);
- if (S.DiagnoseUseOfDecl(Destructor, Kind.getLocation()))
- return ExprError();
- }
- }
- }
+ S.Diag(CurInit.get()->getExprLoc(),
+ diag::warn_cxx98_compat_initializer_list_init)
+ << CurInit.get()->getSourceRange();
- InitListExpr *ILE = cast<InitListExpr>(CurInit.take());
- S.Diag(ILE->getExprLoc(), diag::warn_cxx98_compat_initializer_list_init)
- << ILE->getSourceRange();
- unsigned NumInits = ILE->getNumInits();
- SmallVector<Expr*, 16> Converted(NumInits);
- InitializedEntity HiddenArray = InitializedEntity::InitializeTemporary(
- S.Context.getConstantArrayType(E,
- llvm::APInt(S.Context.getTypeSize(S.Context.getSizeType()),
- NumInits),
- ArrayType::Normal, 0));
- InitializedEntity Element =InitializedEntity::InitializeElement(S.Context,
- 0, HiddenArray);
- for (unsigned i = 0; i < NumInits; ++i) {
- Element.setElementIndex(i);
- ExprResult Init = S.Owned(ILE->getInit(i));
- ExprResult Res = S.PerformCopyInitialization(
- Element, Init.get()->getExprLoc(), Init,
- /*TopLevelOfInitList=*/ true);
- if (Res.isInvalid())
- return ExprError();
- Converted[i] = Res.take();
+ // 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);
}
- InitListExpr *Semantic = new (S.Context)
- InitListExpr(S.Context, ILE->getLBraceLoc(),
- Converted, ILE->getRBraceLoc());
- Semantic->setSyntacticForm(ILE);
- Semantic->setType(Dest);
- Semantic->setInitializesStdInitializerList();
- CurInit = S.Owned(Semantic);
+
+ // Materialize the temporary into memory.
+ MaterializeTemporaryExpr *MTE = new (S.Context)
+ MaterializeTemporaryExpr(CurInit.get()->getType(), CurInit.get(),
+ /*lvalue reference*/ false, ExtendingDecl);
+
+ // Wrap it in a construction of a std::initializer_list<T>.
+ CurInit = S.Owned(
+ new (S.Context) CXXStdInitializerListExpr(Step->Type, MTE));
+
+ // Bind the result, in case the library has given initializer_list a
+ // non-trivial destructor.
+ if (shouldBindAsTemporary(Entity))
+ CurInit = S.MaybeBindToTemporary(CurInit.take());
break;
}
+
case SK_OCLSamplerInit: {
assert(Step->Type->isSamplerT() &&
"Sampler initialization on non sampler type.");
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index fe49153d991..da1e41c2afb 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -2639,6 +2639,10 @@ ExprResult TreeTransform<Derived>::TransformInitializer(Expr *Init,
if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Init))
Init = ICE->getSubExprAsWritten();
+ if (CXXStdInitializerListExpr *ILE =
+ dyn_cast<CXXStdInitializerListExpr>(Init))
+ return TransformInitializer(ILE->getSubExpr(), CXXDirectInit);
+
// If this is not a direct-initializer, we only need to reconstruct
// InitListExprs. Other forms of copy-initialization will be a no-op if
// the initializer is already the right type.
@@ -8549,6 +8553,13 @@ TreeTransform<Derived>::TransformMaterializeTemporaryExpr(
template<typename Derived>
ExprResult
+TreeTransform<Derived>::TransformCXXStdInitializerListExpr(
+ CXXStdInitializerListExpr *E) {
+ return getDerived().TransformExpr(E->getSubExpr());
+}
+
+template<typename Derived>
+ExprResult
TreeTransform<Derived>::TransformObjCStringLiteral(ObjCStringLiteral *E) {
return SemaRef.MaybeBindToTemporary(E);
}
diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp
index 9e0157d7afb..2f5dee8282d 100644
--- a/clang/lib/Serialization/ASTReaderStmt.cpp
+++ b/clang/lib/Serialization/ASTReaderStmt.cpp
@@ -723,7 +723,6 @@ void ASTStmtReader::VisitInitListExpr(InitListExpr *E) {
} else
E->ArrayFillerOrUnionFieldInit = ReadDeclAs<FieldDecl>(Record, Idx);
E->sawArrayRangeDesignator(Record[Idx++]);
- E->setInitializesStdInitializerList(Record[Idx++]);
unsigned NumInits = Record[Idx++];
E->reserveInits(Reader.getContext(), NumInits);
if (isArrayFiller) {
@@ -1227,6 +1226,12 @@ void ASTStmtReader::VisitLambdaExpr(LambdaExpr *E) {
}
}
+void
+ASTStmtReader::VisitCXXStdInitializerListExpr(CXXStdInitializerListExpr *E) {
+ VisitExpr(E);
+ E->SubExpr = Reader.ReadSubExpr();
+}
+
void ASTStmtReader::VisitCXXNamedCastExpr(CXXNamedCastExpr *E) {
VisitExplicitCastExpr(E);
SourceRange R = ReadSourceRange(Record, Idx);
@@ -2161,6 +2166,10 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
S = new (Context) UserDefinedLiteral(Context, Empty);
break;
+ case EXPR_CXX_STD_INITIALIZER_LIST:
+ S = new (Context) CXXStdInitializerListExpr(Empty);
+ break;
+
case EXPR_CXX_BOOL_LITERAL:
S = new (Context) CXXBoolLiteralExpr(Empty);
break;
diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp
index ba6243a51af..ece297f3e53 100644
--- a/clang/lib/Serialization/ASTWriter.cpp
+++ b/clang/lib/Serialization/ASTWriter.cpp
@@ -735,6 +735,7 @@ static void AddStmtsExprs(llvm::BitstreamWriter &Stream,
RECORD(EXPR_CXX_CONST_CAST);
RECORD(EXPR_CXX_FUNCTIONAL_CAST);
RECORD(EXPR_USER_DEFINED_LITERAL);
+ RECORD(EXPR_CXX_STD_INITIALIZER_LIST);
RECORD(EXPR_CXX_BOOL_LITERAL);
RECORD(EXPR_CXX_NULL_PTR_LITERAL);
RECORD(EXPR_CXX_TYPEID_EXPR);
diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp
index 5a8baa9d88a..4b01a218f56 100644
--- a/clang/lib/Serialization/ASTWriterStmt.cpp
+++ b/clang/lib/Serialization/ASTWriterStmt.cpp
@@ -683,7 +683,6 @@ void ASTStmtWriter::VisitInitListExpr(InitListExpr *E) {
else
Writer.AddDeclRef(E->getInitializedFieldInUnion(), Record);
Record.push_back(E->hadArrayRangeDesignator());
- Record.push_back(E->initializesStdInitializerList());
Record.push_back(E->getNumInits());
if (isArrayFiller) {
// ArrayFiller may have filled "holes" due to designated initializer.
@@ -1187,6 +1186,12 @@ void ASTStmtWriter::VisitLambdaExpr(LambdaExpr *E) {
Code = serialization::EXPR_LAMBDA;
}
+void ASTStmtWriter::VisitCXXStdInitializerListExpr(CXXStdInitializerListExpr *E) {
+ VisitExpr(E);
+ Writer.AddStmt(E->getSubExpr());
+ Code = serialization::EXPR_CXX_STD_INITIALIZER_LIST;
+}
+
void ASTStmtWriter::VisitCXXNamedCastExpr(CXXNamedCastExpr *E) {
VisitExplicitCastExpr(E);
Writer.AddSourceRange(SourceRange(E->getOperatorLoc(), E->getRParenLoc()),
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
index a07b72e36f2..db32003e7bf 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -607,6 +607,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
case Stmt::CXXDefaultInitExprClass:
case Stmt::CXXDependentScopeMemberExprClass:
case Stmt::CXXPseudoDestructorExprClass:
+ case Stmt::CXXStdInitializerListExprClass:
case Stmt::CXXTryStmtClass:
case Stmt::CXXTypeidExprClass:
case Stmt::CXXUuidofExprClass:
diff --git a/clang/test/CXX/dcl.decl/dcl.init/dcl.init.list/p3-0x.cpp b/clang/test/CXX/dcl.decl/dcl.init/dcl.init.list/p3-0x.cpp
index d61f6e3d198..58d038366c8 100644
--- a/clang/test/CXX/dcl.decl/dcl.init/dcl.init.list/p3-0x.cpp
+++ b/clang/test/CXX/dcl.decl/dcl.init/dcl.init.list/p3-0x.cpp
@@ -4,7 +4,7 @@ namespace std {
typedef decltype(sizeof(int)) size_t;
template <typename E>
- struct initializer_list
+ struct initializer_list // expected-note 2{{candidate}}
{
const E *p;
size_t n;
@@ -113,10 +113,14 @@ namespace bullet8 {
namespace rdar13395022 {
struct MoveOnly {
- MoveOnly(MoveOnly&&); // expected-note{{copy constructor is implicitly deleted because 'MoveOnly' has a user-declared move constructor}}
+ MoveOnly(MoveOnly&&);
};
void test(MoveOnly mo) {
- auto &&list = {mo}; // expected-error{{call to implicitly-deleted copy constructor of 'rdar13395022::MoveOnly'}}
+ // FIXME: These diagnostics are poor.
+ auto &&list1 = {mo}; // expected-error{{no viable conversion}}
+ MoveOnly (&&list2)[1] = {mo}; // expected-error{{no viable conversion}}
+ std::initializer_list<MoveOnly> &&list3 = {};
+ MoveOnly (&&list4)[1] = {}; // expected-error{{uninitialized}}
}
}
diff --git a/clang/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist-pr12086.cpp b/clang/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist-pr12086.cpp
index 14d2f772918..1f698899c62 100644
--- a/clang/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist-pr12086.cpp
+++ b/clang/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist-pr12086.cpp
@@ -1,18 +1,28 @@
-// RUN: %clang_cc1 -std=c++11 -emit-llvm -o - -verify %s
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++11 -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK-STATIC-BL
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++11 -emit-llvm -o - %s -Dconstexpr= | FileCheck %s --check-prefix=CHECK-DYNAMIC-BL
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++11 -emit-llvm -o - %s -DUSE_END | FileCheck %s --check-prefix=CHECK-STATIC-BE
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++11 -emit-llvm -o - %s -DUSE_END -Dconstexpr= | FileCheck %s --check-prefix=CHECK-DYNAMIC-BE
namespace std {
typedef decltype(sizeof(int)) size_t;
- // libc++'s implementation
template <class _E>
class initializer_list
{
const _E* __begin_;
+#ifdef USE_END
+ const _E* __end_;
+#else
size_t __size_;
+#endif
- initializer_list(const _E* __b, size_t __s)
+ constexpr initializer_list(const _E* __b, size_t __s)
: __begin_(__b),
+#ifdef USE_END
+ __end_(__b + __s)
+#else
__size_(__s)
+#endif
{}
public:
@@ -24,14 +34,98 @@ namespace std {
typedef const _E* iterator;
typedef const _E* const_iterator;
- initializer_list() : __begin_(nullptr), __size_(0) {}
+#ifdef USE_END
+ constexpr initializer_list() : __begin_(nullptr), __end_(nullptr) {}
+
+ size_t size() const {return __end_ - __begin_;}
+ const _E* begin() const {return __begin_;}
+ const _E* end() const {return __end_;}
+#else
+ constexpr initializer_list() : __begin_(nullptr), __size_(0) {}
size_t size() const {return __size_;}
const _E* begin() const {return __begin_;}
const _E* end() const {return __begin_ + __size_;}
+#endif
};
}
-std::initializer_list<std::initializer_list<int>> pleasefail = {
- {1, 2}, {3, 4}, {5, 6} // expected-error {{cannot compile}}
+std::initializer_list<std::initializer_list<int>> nested = {
+ {1, 2}, {3, 4}, {5, 6}
};
+
+// CHECK-STATIC-BL: @_ZGR6nested = 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: {{.*}} { 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-DYNAMIC-BL: @nested = global
+// CHECK-DYNAMIC-BL: @_ZGR6nested = private global [3 x
+// 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 2, 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-DYMAMIC-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 4, 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 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 6, 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: 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: @_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: {{.*}} { 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-DYNAMIC-BE: @nested = global
+// CHECK-DYNAMIC-BE: @_ZGR6nested = private global [3 x
+// 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 2, 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-DYMAMIC-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]* @_ZGR6nested1, i64 1, i64 0),
+// CHECK-DYMAMIC-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: store i32 4, 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 6, 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: 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
+// CHECK-DYNAMIC-BE: store {{.*}}* getelementptr inbounds ([3 x {{.*}}]* @_ZGR6nested, i64 1, i64 0),
+// CHECK-DYNAMIC-BE: {{.*}}** getelementptr inbounds ({{.*}}* @nested, i32 0, i32 1), align 8
diff --git a/clang/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist-startend.cpp b/clang/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist-startend.cpp
index 209ee651385..458dee73c65 100644
--- a/clang/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist-startend.cpp
+++ b/clang/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist-startend.cpp
@@ -32,8 +32,8 @@ namespace std {
};
}
-// CHECK: @_ZL25globalInitList1__initlist = internal global [3 x i32] [i32 1, i32 2, i32 3]
-// CHECK: @globalInitList1 = global {{[^ ]+}} { i32* getelementptr inbounds ([3 x i32]* @_ZL25globalInitList1__initlist, {{[^)]*}}), i32*
+// CHECK: @_ZGR15globalInitList1 = private constant [3 x i32] [i32 1, i32 2, i32 3]
+// CHECK: @globalInitList1 = global {{[^ ]+}} { i32* getelementptr inbounds ([3 x i32]* @_ZGR15globalInitList1, {{[^)]*}}), i32*
std::initializer_list<int> globalInitList1 = {1, 2, 3};
void fn1(int i) {
diff --git a/clang/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp b/clang/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp
index 54d88f565ee..593367c8f13 100644
--- a/clang/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp
+++ b/clang/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp
@@ -47,23 +47,43 @@ struct wantslist1 {
~wantslist1();
};
-// CHECK: @_ZL25globalInitList1__initlist = internal global [3 x i32] [i32 1, i32 2, i32 3]
-// CHECK: @globalInitList1 = global %{{[^ ]+}} { i32* getelementptr inbounds ([3 x i32]* @_ZL25globalInitList1__initlist, i32 0, i32 0), i{{32|64}} 3 }
+// CHECK: @_ZGR15globalInitList1 = private constant [3 x i32] [i32 1, i32 2, i32 3]
+// CHECK: @globalInitList1 = global %{{[^ ]+}} { i32* getelementptr inbounds ([3 x i32]* @_ZGR15globalInitList1, i32 0, i32 0), i{{32|64}} 3 }
std::initializer_list<int> globalInitList1 = {1, 2, 3};
namespace thread_local_global_array {
- // CHECK: @_ZN25thread_local_global_arrayL11x__initlistE = internal thread_local global [4 x i32] [i32 1, i32 2, i32 3, i32 4]
- // CHECK: @_ZN25thread_local_global_array1xE = thread_local global {{.*}} @_ZN25thread_local_global_arrayL11x__initlistE, {{.*}} i64 4
+ // FIXME: We should be able to constant-evaluate this even though the
+ // initializer is not a constant expression (pointers to thread_local
+ // objects aren't really a problem).
+ //
+ // CHECK: @_ZN25thread_local_global_array1xE = thread_local global
+ // CHECK: @_ZGRN25thread_local_global_array1xE = private thread_local global [4 x i32]
std::initializer_list<int> thread_local x = { 1, 2, 3, 4 };
}
-// CHECK: @_ZL25globalInitList2__initlist = internal global [2 x %{{[^ ]*}}] zeroinitializer
-// CHECK: @globalInitList2 = global %{{[^ ]+}} { %[[WITHARG:[^ *]+]]* getelementptr inbounds ([2 x
+// CHECK: @globalInitList2 = global %{{[^ ]+}} zeroinitializer
+// CHECK: @_ZGR15globalInitList2 = private global [2 x %[[WITHARG:[^ ]*]]] zeroinitializer
// CHECK: appending global
+
+
+// thread_local initializer:
+// CHECK: define internal void
+// CHECK: store i32 1, i32* getelementptr inbounds ([4 x i32]* @_ZGRN25thread_local_global_array1xE, i64 0, i64 0)
+// CHECK: store i32 2, i32* getelementptr inbounds ([4 x i32]* @_ZGRN25thread_local_global_array1xE, i64 0, i64 1)
+// CHECK: store i32 3, i32* getelementptr inbounds ([4 x i32]* @_ZGRN25thread_local_global_array1xE, i64 0, i64 2)
+// CHECK: store i32 4, i32* getelementptr inbounds ([4 x i32]* @_ZGRN25thread_local_global_array1xE, i64 0, i64 3)
+// CHECK: store i32* getelementptr inbounds ([4 x i32]* @_ZGRN25thread_local_global_array1xE, i64 0, i64 0),
+// CHECK: i32** getelementptr inbounds ({{.*}}* @_ZN25thread_local_global_array1xE, i32 0, i32 0), align 8
+// CHECK: store i64 4, i64* getelementptr inbounds ({{.*}}* @_ZN25thread_local_global_array1xE, i32 0, i32 1), align 8
+
+
// CHECK: define internal void
-// CHECK: call void @_ZN8witharg1C1ERK10destroyme1(%[[WITHARG]]* getelementptr inbounds ([2 x %[[WITHARG]]]* @_ZL25globalInitList2__initlist, i{{32|64}} 0, i{{32|64}} 0
-// CHECK: call void @_ZN8witharg1C1ERK10destroyme1(%[[WITHARG]]* getelementptr inbounds ([2 x %[[WITHARG]]]* @_ZL25globalInitList2__initlist, i{{32|64}} 0, i{{32|64}} 1
+// CHECK: call void @_ZN8witharg1C1ERK10destroyme1(%[[WITHARG]]* getelementptr inbounds ([2 x %[[WITHARG]]]* @_ZGR15globalInitList2, i{{32|64}} 0, i{{32|64}} 0
+// CHECK: call void @_ZN8witharg1C1ERK10destroyme1(%[[WITHARG]]* getelementptr inbounds ([2 x %[[WITHARG]]]* @_ZGR15globalInitList2, i{{32|64}} 0, i{{32|64}} 1
// CHECK: __cxa_atexit
+// CHECK: store %[[WITHARG]]* getelementptr inbounds ([2 x %[[WITHARG]]]* @_ZGR15globalInitList2, i64 0, i64 0),
+// CHECK: %[[WITHARG]]** getelementptr inbounds (%{{.*}}* @globalInitList2, i32 0, i32 0), align 8
+// CHECK: store i64 2, i64* getelementptr inbounds (%{{.*}}* @globalInitList2, i32 0, i32 1), align 8
// CHECK: call void @_ZN10destroyme1D1Ev
// CHECK: call void @_ZN10destroyme1D1Ev
std::initializer_list<witharg1> globalInitList2 = {
@@ -281,10 +301,56 @@ namespace dtors {
S();
~S();
};
+ void z();
+
+ // CHECK: define void @_ZN5dtors1fEv(
void f() {
+ // CHECK: call void @_ZN5dtors1SC1Ev(%"struct.dtors::S"* %arrayinit.begin)
+ // CHECK: call void @_ZN5dtors1SC1Ev(%"struct.dtors::S"* %arrayinit.element)
std::initializer_list<S>{ S(), S() };
+
+ // Destruction loop for underlying array.
+ // CHECK: br label
+ // CHECK: call void @_ZN5dtors1SD1Ev(
+ // CHECK: br i1
+
+ // CHECK: call void @_ZN5dtors1zEv(
+ z();
+
+ // CHECK-NOT: call void @_ZN5dtors1SD1Ev(
}
+
+ // CHECK: define void @_ZN5dtors1gEv(
void g() {
+ // CHECK: call void @_ZN5dtors1SC1Ev(%"struct.dtors::S"* %arrayinit.begin)
+ // CHECK: call void @_ZN5dtors1SC1Ev(%"struct.dtors::S"* %arrayinit.element)
auto x = std::initializer_list<S>{ S(), S() };
+
+ // Destruction loop for underlying array.
+ // CHECK: br label
+ // CHECK: call void @_ZN5dtors1SD1Ev(
+ // CHECK: br i1
+
+ // CHECK: call void @_ZN5dtors1zEv(
+ z();
+
+ // CHECK-NOT: call void @_ZN5dtors1SD1Ev(
+ }
+
+ // CHECK: define void @_ZN5dtors1hEv(
+ void h() {
+ // CHECK: call void @_ZN5dtors1SC1Ev(%"struct.dtors::S"* %arrayinit.begin)
+ // CHECK: call void @_ZN5dtors1SC1Ev(%"struct.dtors::S"* %arrayinit.element)
+ std::initializer_list<S> x = { S(), S() };
+
+ // CHECK-NOT: call void @_ZN5dtors1SD1Ev(
+
+ // CHECK: call void @_ZN5dtors1zEv(
+ z();
+
+ // Destruction loop for underlying array.
+ // CHECK: br label
+ // CHECK: call void @_ZN5dtors1SD1Ev(
+ // CHECK: br i1
}
}
diff --git a/clang/test/SemaCXX/constant-expression-cxx11.cpp b/clang/test/SemaCXX/constant-expression-cxx11.cpp
index 8968ba05f90..e4db1b3405a 100644
--- a/clang/test/SemaCXX/constant-expression-cxx11.cpp
+++ b/clang/test/SemaCXX/constant-expression-cxx11.cpp
@@ -1596,3 +1596,44 @@ namespace AfterError {
}
constexpr int k = error(); // expected-error {{must be initialized by a constant expression}}
}
+
+namespace std {
+ typedef decltype(sizeof(int)) size_t;
+
+ template <class _E>
+ class initializer_list
+ {
+ const _E* __begin_;
+ size_t __size_;
+
+ constexpr initializer_list(const _E* __b, size_t __s)
+ : __begin_(__b),
+ __size_(__s)
+ {}
+
+ public:
+ typedef _E value_type;
+ typedef const _E& reference;
+ typedef const _E& const_reference;
+ typedef size_t size_type;
+
+ typedef const _E* iterator;
+ typedef const _E* const_iterator;
+
+ constexpr initializer_list() : __begin_(nullptr), __size_(0) {}
+
+ constexpr size_t size() const {return __size_;}
+ constexpr const _E* begin() const {return __begin_;}
+ constexpr const _E* end() const {return __begin_ + __size_;}
+ };
+}
+
+namespace InitializerList {
+ constexpr int sum(const int *b, const int *e) {
+ return b != e ? *b + sum(b+1, e) : 0;
+ }
+ constexpr int sum(std::initializer_list<int> ints) {
+ return sum(ints.begin(), ints.end());
+ }
+ static_assert(sum({1, 2, 3, 4, 5}) == 15, "");
+}
diff --git a/clang/test/SemaCXX/constant-expression-cxx1y.cpp b/clang/test/SemaCXX/constant-expression-cxx1y.cpp
index 40a98d4ca9f..af44bf8d744 100644
--- a/clang/test/SemaCXX/constant-expression-cxx1y.cpp
+++ b/clang/test/SemaCXX/constant-expression-cxx1y.cpp
@@ -725,3 +725,43 @@ namespace modify_temporary_during_construction {
static_assert(a.y == 54, "");
constexpr int k = a.temporary++; // expected-error {{constant expression}} expected-note {{outside the expression that created the temporary}}
}
+
+namespace std {
+ typedef decltype(sizeof(int)) size_t;
+
+ template <class _E>
+ class initializer_list
+ {
+ const _E* __begin_;
+ size_t __size_;
+
+ constexpr initializer_list(const _E* __b, size_t __s)
+ : __begin_(__b),
+ __size_(__s)
+ {}
+
+ public:
+ typedef _E value_type;
+ typedef const _E& reference;
+ typedef const _E& const_reference;
+ typedef size_t size_type;
+
+ typedef const _E* iterator;
+ typedef const _E* const_iterator;
+
+ constexpr initializer_list() : __begin_(nullptr), __size_(0) {}
+
+ constexpr size_t size() const {return __size_;}
+ constexpr const _E* begin() const {return __begin_;}
+ constexpr const _E* end() const {return __begin_ + __size_;}
+ };
+}
+
+namespace InitializerList {
+ constexpr int sum(std::initializer_list<int> ints) {
+ int total = 0;
+ for (int n : ints) total += n;
+ return total;
+ }
+ static_assert(sum({1, 2, 3, 4, 5}) == 15, "");
+}
diff --git a/clang/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp b/clang/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp
index 0f7eb77c864..071098440cd 100644
--- a/clang/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp
+++ b/clang/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp
@@ -144,7 +144,7 @@ namespace PR12119 {
template<typename T> void g(std::initializer_list<std::initializer_list<T>>);
void foo() {
- f({0, {1}});
+ f({0, {1}}); // expected-warning{{braces around scalar initializer}}
g({{0, 1}, {2, 3}});
std::initializer_list<int> il = {1, 2};
g({il, {2, 3}});
diff --git a/clang/tools/libclang/CXCursor.cpp b/clang/tools/libclang/CXCursor.cpp
index 2cdb71bb022..5f798f92c60 100644
--- a/clang/tools/libclang/CXCursor.cpp
+++ b/clang/tools/libclang/CXCursor.cpp
@@ -216,6 +216,7 @@ CXCursor cxcursor::MakeCXCursor(const Stmt *S, const Decl *Parent,
case Stmt::CXXBindTemporaryExprClass:
case Stmt::CXXDefaultArgExprClass:
case Stmt::CXXDefaultInitExprClass:
+ case Stmt::CXXStdInitializerListExprClass:
case Stmt::CXXScalarValueInitExprClass:
case Stmt::CXXUuidofExprClass:
case Stmt::ChooseExprClass:
diff --git a/clang/tools/libclang/RecursiveASTVisitor.h b/clang/tools/libclang/RecursiveASTVisitor.h
index e45545ed1ad..0958d52e79c 100644
--- a/clang/tools/libclang/RecursiveASTVisitor.h
+++ b/clang/tools/libclang/RecursiveASTVisitor.h
@@ -2095,6 +2095,7 @@ DEF_TRAVERSE_STMT(CXXDefaultInitExpr, { })
DEF_TRAVERSE_STMT(CXXDeleteExpr, { })
DEF_TRAVERSE_STMT(ExprWithCleanups, { })
DEF_TRAVERSE_STMT(CXXNullPtrLiteralExpr, { })
+DEF_TRAVERSE_STMT(CXXStdInitializerListExpr, { })
DEF_TRAVERSE_STMT(CXXPseudoDestructorExpr, {
TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc()));
if (TypeSourceInfo *ScopeInfo = S->getScopeTypeInfo())
OpenPOWER on IntegriCloud