[cfe-commits] r145186 - in /cfe/trunk: include/clang/Basic/DiagnosticSemaKinds.td include/clang/Sema/Initialization.h lib/AST/ExprClassification.cpp lib/CodeGen/CGExpr.cpp lib/Sema/SemaDecl.cpp lib/Sema/SemaInit.cpp test/CodeGenCXX/cxx0x-initializer-references.cpp test/SemaCXX/cxx0x-initializer-references.cpp
Sebastian Redl
sebastian.redl at getdesigned.at
Sun Nov 27 08:50:07 PST 2011
Author: cornedbee
Date: Sun Nov 27 10:50:07 2011
New Revision: 145186
URL: http://llvm.org/viewvc/llvm-project?rev=145186&view=rev
Log:
Reference initialization with initializer lists.
This supports single-element initializer lists for references according to DR1288, as well as creating temporaries and binding to them for other initializer lists.
Added:
cfe/trunk/test/CodeGenCXX/cxx0x-initializer-references.cpp
cfe/trunk/test/SemaCXX/cxx0x-initializer-references.cpp
Modified:
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
cfe/trunk/include/clang/Sema/Initialization.h
cfe/trunk/lib/AST/ExprClassification.cpp
cfe/trunk/lib/CodeGen/CGExpr.cpp
cfe/trunk/lib/Sema/SemaDecl.cpp
cfe/trunk/lib/Sema/SemaInit.cpp
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=145186&r1=145185&r2=145186&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Sun Nov 27 10:50:07 2011
@@ -1034,6 +1034,9 @@
def err_not_reference_to_const_init : Error<
"%select{non-const|volatile}0 lvalue reference to type %1 cannot be "
"initialized with a %select{value|temporary}2 of type %3">;
+def err_lvalue_reference_bind_to_initlist : Error<
+ "%select{non-const|volatile}0 lvalue reference to type %1 cannot bind to an "
+ "initializer list temporary">;
def err_lvalue_reference_bind_to_temporary : Error<
"%select{non-const|volatile}0 lvalue reference to type %1 cannot bind to a "
"temporary of type %2">;
Modified: cfe/trunk/include/clang/Sema/Initialization.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Initialization.h?rev=145186&r1=145185&r2=145186&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Initialization.h (original)
+++ cfe/trunk/include/clang/Sema/Initialization.h Sun Nov 27 10:50:07 2011
@@ -530,6 +530,10 @@
SK_ListInitialization,
/// \brief Perform list-initialization with a constructor.
SK_ListConstructorCall,
+ /// \brief Unwrap the single-element initializer list for a reference.
+ SK_UnwrapInitList,
+ /// \brief Rewrap the single-element initializer list for a reference.
+ SK_RewrapInitList,
/// \brief Perform initialization via a constructor.
SK_ConstructorInitialization,
/// \brief Zero-initialize the object
@@ -579,8 +583,12 @@
} Function;
/// \brief When Kind = SK_ConversionSequence, the implicit conversion
- /// sequence
+ /// sequence.
ImplicitConversionSequence *ICS;
+
+ /// \brief When Kind = SK_RewrapInitList, the syntactic form of the
+ /// wrapping list.
+ InitListExpr *WrappingSyntacticList;
};
void Destroy();
@@ -853,6 +861,10 @@
/// retaining it).
void AddProduceObjCObjectStep(QualType T);
+ /// \brief Add steps to unwrap a initializer list for a reference around a
+ /// single element and rewrap it at the end.
+ void RewrapReferenceInitList(QualType T, InitListExpr *Syntactic);
+
/// \brief Note that this initialization sequence failed.
void SetFailed(FailureKind Failure) {
SequenceKind = FailedSequence;
Modified: cfe/trunk/lib/AST/ExprClassification.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprClassification.cpp?rev=145186&r1=145185&r2=145186&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ExprClassification.cpp (original)
+++ cfe/trunk/lib/AST/ExprClassification.cpp Sun Nov 27 10:50:07 2011
@@ -93,7 +93,6 @@
const LangOptions &Lang = Ctx.getLangOptions();
switch (E->getStmtClass()) {
- // First come the expressions that are always lvalues, unconditionally.
case Stmt::NoStmtClass:
#define ABSTRACT_STMT(Kind)
#define STMT(Kind, Base) case Expr::Kind##Class:
@@ -101,6 +100,8 @@
#include "clang/AST/StmtNodes.inc"
llvm_unreachable("cannot classify a statement");
break;
+
+ // First come the expressions that are always lvalues, unconditionally.
case Expr::ObjCIsaExprClass:
// C++ [expr.prim.general]p1: A string literal is an lvalue.
case Expr::StringLiteralClass:
@@ -122,6 +123,7 @@
// FIXME: ObjC++0x might have different rules
case Expr::ObjCIvarRefExprClass:
return Cl::CL_LValue;
+
// C99 6.5.2.5p5 says that compound literals are lvalues.
// In C++, they're class temporaries.
case Expr::CompoundLiteralExprClass:
@@ -157,7 +159,6 @@
case Expr::ObjCProtocolExprClass:
case Expr::ObjCStringLiteralClass:
case Expr::ParenListExprClass:
- case Expr::InitListExprClass:
case Expr::SizeOfPackExprClass:
case Expr::SubstNonTypeTemplateParmPackExprClass:
case Expr::AsTypeExprClass:
@@ -229,8 +230,7 @@
}
case Expr::OpaqueValueExprClass:
- return ClassifyExprValueKind(Lang, E,
- cast<OpaqueValueExpr>(E)->getValueKind());
+ return ClassifyExprValueKind(Lang, E, E->getValueKind());
// Pseudo-object expressions can produce l-values with reference magic.
case Expr::PseudoObjectExprClass:
@@ -240,8 +240,7 @@
// Implicit casts are lvalues if they're lvalue casts. Other than that, we
// only specifically record class temporaries.
case Expr::ImplicitCastExprClass:
- return ClassifyExprValueKind(Lang, E,
- cast<ImplicitCastExpr>(E)->getValueKind());
+ return ClassifyExprValueKind(Lang, E, E->getValueKind());
// C++ [expr.prim.general]p4: The presence of parentheses does not affect
// whether the expression is an lvalue.
@@ -337,29 +336,40 @@
case Expr::VAArgExprClass:
return ClassifyUnnamed(Ctx, E->getType());
-
+
case Expr::DesignatedInitExprClass:
return ClassifyInternal(Ctx, cast<DesignatedInitExpr>(E)->getInit());
-
+
case Expr::StmtExprClass: {
const CompoundStmt *S = cast<StmtExpr>(E)->getSubStmt();
if (const Expr *LastExpr = dyn_cast_or_null<Expr>(S->body_back()))
return ClassifyUnnamed(Ctx, LastExpr->getType());
return Cl::CL_PRValue;
}
-
+
case Expr::CXXUuidofExprClass:
return Cl::CL_LValue;
-
+
case Expr::PackExpansionExprClass:
return ClassifyInternal(Ctx, cast<PackExpansionExpr>(E)->getPattern());
-
+
case Expr::MaterializeTemporaryExprClass:
return cast<MaterializeTemporaryExpr>(E)->isBoundToLvalueReference()
? Cl::CL_LValue
: Cl::CL_XValue;
+
+ case Expr::InitListExprClass:
+ // An init list can be an lvalue if it is bound to a reference and
+ // contains only one element. In that case, we look at that element
+ // for an exact classification. Init list creation takes care of the
+ // value kind for us, so we only need to fine-tune.
+ if (E->isRValue())
+ return ClassifyExprValueKind(Lang, E, E->getValueKind());
+ assert(cast<InitListExpr>(E)->getNumInits() == 1 &&
+ "Only 1-element init lists can be glvalues.");
+ return ClassifyInternal(Ctx, cast<InitListExpr>(E)->getInit(0));
}
-
+
llvm_unreachable("unhandled expression kind in classification");
return Cl::CL_LValue;
}
Modified: cfe/trunk/lib/CodeGen/CGExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExpr.cpp?rev=145186&r1=145185&r2=145186&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExpr.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExpr.cpp Sun Nov 27 10:50:07 2011
@@ -210,6 +210,13 @@
const CXXDestructorDecl *&ReferenceTemporaryDtor,
QualType &ObjCARCReferenceLifetimeType,
const NamedDecl *InitializedDecl) {
+ // Look through single-element init lists that claim to be lvalues. They're
+ // just syntactic wrappers in this case.
+ if (const InitListExpr *ILE = dyn_cast<InitListExpr>(E)) {
+ if (ILE->getNumInits() == 1 && ILE->isGLValue())
+ E = ILE->getInit(0);
+ }
+
// Look through expressions for materialized temporaries (for now).
if (const MaterializeTemporaryExpr *M
= dyn_cast<MaterializeTemporaryExpr>(E)) {
@@ -669,6 +676,10 @@
return EmitObjCEncodeExprLValue(cast<ObjCEncodeExpr>(E));
case Expr::PseudoObjectExprClass:
return EmitPseudoObjectLValue(cast<PseudoObjectExpr>(E));
+ case Expr::InitListExprClass:
+ assert(cast<InitListExpr>(E)->getNumInits() == 1 &&
+ "Only single-element init list can be lvalue.");
+ return EmitLValue(cast<InitListExpr>(E)->getInit(0));
case Expr::BlockDeclRefExprClass:
return EmitBlockDeclRefLValue(cast<BlockDeclRefExpr>(E));
@@ -728,7 +739,7 @@
case Expr::CXXConstCastExprClass:
case Expr::ObjCBridgedCastExprClass:
return EmitCastLValue(cast<CastExpr>(E));
-
+
case Expr::MaterializeTemporaryExprClass:
return EmitMaterializeTemporaryExpr(cast<MaterializeTemporaryExpr>(E));
}
Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=145186&r1=145185&r2=145186&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Sun Nov 27 10:50:07 2011
@@ -6199,7 +6199,7 @@
// "ary" transitions from a VariableArrayType to a ConstantArrayType.
if (!VDecl->isInvalidDecl() && (DclT != SavT)) {
VDecl->setType(DclT);
- Init->setType(DclT);
+ Init->setType(DclT.getNonReferenceType());
}
// Check any implicit conversions within the expression.
Modified: cfe/trunk/lib/Sema/SemaInit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.cpp?rev=145186&r1=145185&r2=145186&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaInit.cpp (original)
+++ cfe/trunk/lib/Sema/SemaInit.cpp Sun Nov 27 10:50:07 2011
@@ -989,8 +989,7 @@
}
Expr *expr = IList->getInit(Index);
- if (isa<InitListExpr>(expr)) {
- // FIXME: Allowed in C++11.
+ if (isa<InitListExpr>(expr) && !SemaRef.getLangOptions().CPlusPlus0x) {
if (!VerifyOnly)
SemaRef.Diag(IList->getLocStart(), diag::err_init_non_aggr_init_list)
<< DeclType << IList->getSourceRange();
@@ -2385,6 +2384,8 @@
case SK_QualificationConversionLValue:
case SK_ListInitialization:
case SK_ListConstructorCall:
+ case SK_UnwrapInitList:
+ case SK_RewrapInitList:
case SK_ConstructorInitialization:
case SK_ZeroInitialization:
case SK_CAssignment:
@@ -2761,6 +2762,21 @@
Steps.push_back(S);
}
+void InitializationSequence::RewrapReferenceInitList(QualType T,
+ InitListExpr *Syntactic) {
+ assert(Syntactic->getNumInits() == 1 &&
+ "Can only rewrap trivial init lists.");
+ Step S;
+ S.Kind = SK_UnwrapInitList;
+ S.Type = Syntactic->getInit(0)->getType();
+ Steps.insert(Steps.begin(), S);
+
+ S.Kind = SK_RewrapInitList;
+ S.Type = T;
+ S.WrappingSyntacticList = Syntactic;
+ Steps.push_back(S);
+}
+
void InitializationSequence::SetOverloadFailure(FailureKind Failure,
OverloadingResult Result) {
setSequenceKind(FailedSequence);
@@ -2799,6 +2815,114 @@
}
}
+static bool
+ResolveOverloadedFunctionForReferenceBinding(Sema &S,
+ Expr *Initializer,
+ QualType &SourceType,
+ QualType &UnqualifiedSourceType,
+ QualType UnqualifiedTargetType,
+ InitializationSequence &Sequence) {
+ if (S.Context.getCanonicalType(UnqualifiedSourceType) ==
+ S.Context.OverloadTy) {
+ DeclAccessPair Found;
+ bool HadMultipleCandidates = false;
+ if (FunctionDecl *Fn
+ = S.ResolveAddressOfOverloadedFunction(Initializer,
+ UnqualifiedTargetType,
+ false, Found,
+ &HadMultipleCandidates)) {
+ Sequence.AddAddressOverloadResolutionStep(Fn, Found,
+ HadMultipleCandidates);
+ SourceType = Fn->getType();
+ UnqualifiedSourceType = SourceType.getUnqualifiedType();
+ } else if (!UnqualifiedTargetType->isRecordType()) {
+ Sequence.SetFailed(InitializationSequence::FK_AddressOfOverloadFailed);
+ return true;
+ }
+ }
+ return false;
+}
+
+static void TryReferenceInitializationCore(Sema &S,
+ const InitializedEntity &Entity,
+ const InitializationKind &Kind,
+ Expr *Initializer,
+ QualType cv1T1, QualType T1,
+ Qualifiers T1Quals,
+ QualType cv2T2, QualType T2,
+ Qualifiers T2Quals,
+ InitializationSequence &Sequence);
+
+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,
+ const InitializationKind &Kind,
+ InitListExpr *InitList,
+ InitializationSequence &Sequence)
+{
+ // First, catch C++03 where this isn't possible.
+ if (!S.getLangOptions().CPlusPlus0x) {
+ Sequence.SetFailed(InitializationSequence::FK_ReferenceBindingToInitList);
+ return;
+ }
+
+ QualType DestType = Entity.getType();
+ QualType cv1T1 = DestType->getAs<ReferenceType>()->getPointeeType();
+ Qualifiers T1Quals;
+ QualType T1 = S.Context.getUnqualifiedArrayType(cv1T1, T1Quals);
+
+ // Reference initialization via an initializer list works thus:
+ // If the initializer list consists of a single element that is
+ // reference-related to the referenced type, bind directly to that element
+ // (possibly creating temporaries).
+ // Otherwise, initialize a temporary with the initializer list and
+ // bind to that.
+ if (InitList->getNumInits() == 1) {
+ Expr *Initializer = InitList->getInit(0);
+ QualType cv2T2 = Initializer->getType();
+ Qualifiers T2Quals;
+ QualType T2 = S.Context.getUnqualifiedArrayType(cv2T2, T2Quals);
+
+ // If this fails, creating a temporary wouldn't work either.
+ if (ResolveOverloadedFunctionForReferenceBinding(S, Initializer, cv2T2, T2,
+ T1, Sequence))
+ return;
+
+ SourceLocation DeclLoc = Initializer->getLocStart();
+ bool dummy1, dummy2, dummy3;
+ Sema::ReferenceCompareResult RefRelationship
+ = S.CompareReferenceRelationship(DeclLoc, cv1T1, cv2T2, dummy1,
+ dummy2, dummy3);
+ if (RefRelationship >= Sema::Ref_Related) {
+ // Try to bind the reference here.
+ TryReferenceInitializationCore(S, Entity, Kind, Initializer, cv1T1, T1,
+ T1Quals, cv2T2, T2, T2Quals, Sequence);
+ if (Sequence)
+ Sequence.RewrapReferenceInitList(cv1T1, InitList);
+ return;
+ }
+ }
+
+ // Not reference-related. Create a temporary and bind to that.
+ InitializedEntity TempEntity = InitializedEntity::InitializeTemporary(cv1T1);
+
+ TryListInitialization(S, TempEntity, Kind, InitList, Sequence);
+ if (Sequence) {
+ if (DestType->isRValueReferenceType() ||
+ (T1Quals.hasConst() && !T1Quals.hasVolatile()))
+ Sequence.AddReferenceBindingStep(cv1T1, /*bindingTemporary=*/true);
+ else
+ Sequence.SetFailed(
+ InitializationSequence::FK_NonConstLValueReferenceBindingToTemporary);
+ }
+}
+
/// \brief Attempt list initialization (C++0x [dcl.init.list])
static void TryListInitialization(Sema &S,
const InitializedEntity &Entity,
@@ -2814,11 +2938,11 @@
Sequence.SetFailed(InitializationSequence::FK_TooManyInitsForScalar);
return;
}
- // FIXME: C++0x defines behavior for these two cases.
if (DestType->isReferenceType()) {
- Sequence.SetFailed(InitializationSequence::FK_ReferenceBindingToInitList);
+ TryReferenceListInitialization(S, Entity, Kind, InitList, Sequence);
return;
}
+ // FIXME: C++11 defines behavior for this case.
if (DestType->isRecordType() && !DestType->isAggregateType()) {
Sequence.SetFailed(InitializationSequence::FK_InitListBadDestinationType);
return;
@@ -3041,27 +3165,31 @@
QualType cv2T2 = Initializer->getType();
Qualifiers T2Quals;
QualType T2 = S.Context.getUnqualifiedArrayType(cv2T2, T2Quals);
- SourceLocation DeclLoc = Initializer->getLocStart();
// If the initializer is the address of an overloaded function, try
// to resolve the overloaded function. If all goes well, T2 is the
// type of the resulting function.
- if (S.Context.getCanonicalType(T2) == S.Context.OverloadTy) {
- DeclAccessPair Found;
- bool HadMultipleCandidates = false;
- if (FunctionDecl *Fn
- = S.ResolveAddressOfOverloadedFunction(Initializer, T1, false, Found,
- &HadMultipleCandidates)) {
- Sequence.AddAddressOverloadResolutionStep(Fn, Found,
- HadMultipleCandidates);
- cv2T2 = Fn->getType();
- T2 = cv2T2.getUnqualifiedType();
- } else if (!T1->isRecordType()) {
- Sequence.SetFailed(InitializationSequence::FK_AddressOfOverloadFailed);
- return;
- }
- }
+ if (ResolveOverloadedFunctionForReferenceBinding(S, Initializer, cv2T2, T2,
+ T1, Sequence))
+ return;
+
+ // Delegate everything else to a subfunction.
+ TryReferenceInitializationCore(S, Entity, Kind, Initializer, cv1T1, T1,
+ T1Quals, cv2T2, T2, T2Quals, Sequence);
+}
+/// \brief Reference initialization without resolving overloaded functions.
+static void TryReferenceInitializationCore(Sema &S,
+ const InitializedEntity &Entity,
+ const InitializationKind &Kind,
+ Expr *Initializer,
+ QualType cv1T1, QualType T1,
+ Qualifiers T1Quals,
+ QualType cv2T2, QualType T2,
+ Qualifiers T2Quals,
+ InitializationSequence &Sequence) {
+ QualType DestType = Entity.getType();
+ SourceLocation DeclLoc = Initializer->getLocStart();
// Compute some basic properties of the types and the initializer.
bool isLValueRef = DestType->isLValueReferenceType();
bool isRValueRef = !isLValueRef;
@@ -4486,6 +4614,8 @@
case SK_ConversionSequence:
case SK_ListConstructorCall:
case SK_ListInitialization:
+ case SK_UnwrapInitList:
+ case SK_RewrapInitList:
case SK_CAssignment:
case SK_StringInit:
case SK_ObjCObjectConversion:
@@ -4746,22 +4876,59 @@
case SK_ListInitialization: {
InitListExpr *InitList = cast<InitListExpr>(CurInit.get());
- QualType Ty = Step->Type;
- InitListChecker PerformInitList(S, Entity, InitList,
- ResultType ? *ResultType : Ty, /*VerifyOnly=*/false,
+ // 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 = ResultType && (*ResultType)->isReferenceType();
+ InitializedEntity TempEntity = InitializedEntity::InitializeTemporary(Ty);
+ InitListChecker PerformInitList(S, IsTemporary ? TempEntity : Entity,
+ InitList, Ty, /*VerifyOnly=*/false,
Kind.getKind() != InitializationKind::IK_Direct ||
!S.getLangOptions().CPlusPlus0x);
if (PerformInitList.HadError())
return ExprError();
+ if (ResultType) {
+ if ((*ResultType)->isRValueReferenceType())
+ Ty = S.Context.getRValueReferenceType(Ty);
+ else if ((*ResultType)->isLValueReferenceType())
+ Ty = S.Context.getLValueReferenceType(Ty,
+ (*ResultType)->getAs<LValueReferenceType>()->isSpelledAsLValue());
+ *ResultType = Ty;
+ }
+
+ InitListExpr *StructuredInitList =
+ PerformInitList.getFullyStructuredList();
CurInit.release();
- CurInit = S.Owned(PerformInitList.getFullyStructuredList());
+ CurInit = S.Owned(StructuredInitList);
break;
}
case SK_ListConstructorCall:
assert(false && "List constructor calls not yet supported.");
+ case SK_UnwrapInitList:
+ CurInit = S.Owned(cast<InitListExpr>(CurInit.take())->getInit(0));
+ break;
+
+ case SK_RewrapInitList: {
+ Expr *E = CurInit.take();
+ InitListExpr *Syntactic = Step->WrappingSyntacticList;
+ InitListExpr *ILE = new (S.Context) InitListExpr(S.Context,
+ Syntactic->getLBraceLoc(), &E, 1, Syntactic->getRBraceLoc());
+ ILE->setSyntacticForm(Syntactic);
+ ILE->setType(E->getType());
+ ILE->setValueKind(E->getValueKind());
+ CurInit = S.Owned(ILE);
+ break;
+ }
+
case SK_ConstructorInitialization: {
unsigned NumArgs = Args.size();
CXXConstructorDecl *Constructor
@@ -5081,6 +5248,16 @@
break;
case FK_NonConstLValueReferenceBindingToTemporary:
+ if (isa<InitListExpr>(Args[0])) {
+ S.Diag(Kind.getLocation(),
+ diag::err_lvalue_reference_bind_to_initlist)
+ << DestType.getNonReferenceType().isVolatileQualified()
+ << DestType.getNonReferenceType()
+ << Args[0]->getSourceRange();
+ break;
+ }
+ // Intentional fallthrough
+
case FK_NonConstLValueReferenceBindingToUnrelated:
S.Diag(Kind.getLocation(),
Failure == FK_NonConstLValueReferenceBindingToTemporary
@@ -5446,9 +5623,11 @@
case SK_QualificationConversionRValue:
OS << "qualification conversion (rvalue)";
+ break;
case SK_QualificationConversionXValue:
OS << "qualification conversion (xvalue)";
+ break;
case SK_QualificationConversionLValue:
OS << "qualification conversion (lvalue)";
@@ -5468,6 +5647,14 @@
OS << "list initialization via constructor";
break;
+ case SK_UnwrapInitList:
+ OS << "unwrap reference initializer list";
+ break;
+
+ case SK_RewrapInitList:
+ OS << "rewrap reference initializer list";
+ break;
+
case SK_ConstructorInitialization:
OS << "constructor initialization";
break;
Added: cfe/trunk/test/CodeGenCXX/cxx0x-initializer-references.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/cxx0x-initializer-references.cpp?rev=145186&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenCXX/cxx0x-initializer-references.cpp (added)
+++ cfe/trunk/test/CodeGenCXX/cxx0x-initializer-references.cpp Sun Nov 27 10:50:07 2011
@@ -0,0 +1,69 @@
+// RUN: %clang_cc1 -std=c++11 -S -emit-llvm -o - %s | FileCheck %s
+
+namespace reference {
+ struct A {
+ int i1, i2;
+ };
+
+ void single_init() {
+ // No superfluous instructions allowed here, they could be
+ // hiding extra temporaries.
+
+ // CHECK: store i32 1, i32*
+ // CHECK-NEXT: store i32* %{{.*}}, i32**
+ const int &cri2a = 1;
+
+ // CHECK-NEXT: store i32 1, i32*
+ // CHECK-NEXT: store i32* %{{.*}}, i32**
+ const int &cri1a = {1};
+
+ // CHECK-NEXT: store i32 1, i32*
+ int i = 1;
+ // CHECK-NEXT: store i32* %{{.*}}, i32**
+ int &ri1a = {i};
+
+ // CHECK-NEXT: bitcast
+ // CHECK-NEXT: memcpy
+ A a{1, 2};
+ // CHECK-NEXT: store %{{.*}}* %{{.*}}, %{{.*}}** %
+ A &ra1a = {a};
+
+ // CHECK-NEXT: ret
+ }
+
+ void reference_to_aggregate() {
+ // CHECK: getelementptr {{.*}}, i32 0, i32 0
+ // CHECK-NEXT: store i32 1
+ // CHECK-NEXT: getelementptr {{.*}}, i32 0, i32 1
+ // CHECK-NEXT: store i32 2
+ // CHECK-NEXT: store %{{.*}}* %{{.*}}, %{{.*}}** %{{.*}}, align
+ const A &ra1{1, 2};
+
+ // CHECK-NEXT: getelementptr inbounds [3 x i32]* %{{.*}}, i{{32|64}} 0, i{{32|64}} 0
+ // CHECK-NEXT: store i32 1
+ // CHECK-NEXT: getelementptr inbounds i32* %{{.*}}, i{{32|64}} 1
+ // CHECK-NEXT: store i32 2
+ // CHECK-NEXT: getelementptr inbounds i32* %{{.*}}, i{{32|64}} 1
+ // CHECK-NEXT: store i32 3
+ // CHECK-NEXT: store [3 x i32]* %{{.*}}, [3 x i32]** %{{.*}}, align
+ const int (&arrayRef)[] = {1, 2, 3};
+
+ // CHECK-NEXT: ret
+ }
+
+ struct B {
+ B();
+ ~B();
+ };
+
+ void single_init_temp_cleanup()
+ {
+ // Ensure lifetime extension.
+
+ // CHECK: call void @_ZN9reference1BC1Ev
+ // CHECK-NEXT: store %{{.*}}* %{{.*}}, %{{.*}}** %
+ const B &rb{ B() };
+ // CHECK: call void @_ZN9reference1BD1Ev
+ }
+
+}
Added: cfe/trunk/test/SemaCXX/cxx0x-initializer-references.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx0x-initializer-references.cpp?rev=145186&view=auto
==============================================================================
--- cfe/trunk/test/SemaCXX/cxx0x-initializer-references.cpp (added)
+++ cfe/trunk/test/SemaCXX/cxx0x-initializer-references.cpp Sun Nov 27 10:50:07 2011
@@ -0,0 +1,31 @@
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+
+namespace reference {
+ struct A {
+ int i1, i2;
+ };
+
+ void single_init() {
+ const int &cri1a = {1};
+ const int &cri1b{1};
+
+ int i = 1;
+ int &ri1a = {i};
+ int &ri1b{i};
+
+ int &ri2 = {1}; // expected-error {{cannot bind to an initializer list temporary}}
+
+ A a{1, 2};
+ A &ra1a = {a};
+ A &ra1b{a};
+ }
+
+ void reference_to_aggregate() {
+ const A &ra1{1, 2};
+ A &ra2{1, 2}; // expected-error {{cannot bind to an initializer list temporary}}
+
+ const int (&arrayRef)[] = {1, 2, 3};
+ static_assert(sizeof(arrayRef) == 3 * sizeof(int), "bad array size");
+ }
+
+}
More information about the cfe-commits
mailing list