From: Richard Smith Date: Thu, 17 Jul 2014 05:12:35 +0000 (+0000) Subject: Track the difference between X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=01ee2dcc3034eca657a14a7af725026e1a7de939;p=clang Track the difference between -- a constructor list initialization that unpacked an initializer list into constructor arguments and -- a list initialization that created as std::initializer_list and passed it as the first argument to a constructor in the AST. Use this flag while instantiating templates to provide the right semantics for the resulting initialization. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@213224 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h index 5178406799..d883a32e0e 100644 --- a/include/clang/AST/ExprCXX.h +++ b/include/clang/AST/ExprCXX.h @@ -1077,6 +1077,7 @@ private: bool Elidable : 1; bool HadMultipleCandidates : 1; bool ListInitialization : 1; + bool StdInitListInitialization : 1; bool ZeroInitialization : 1; unsigned ConstructKind : 2; Stmt **Args; @@ -1088,6 +1089,7 @@ protected: ArrayRef Args, bool HadMultipleCandidates, bool ListInitialization, + bool StdInitListInitialization, bool ZeroInitialization, ConstructionKind ConstructKind, SourceRange ParenOrBraceRange); @@ -1114,6 +1116,7 @@ public: ArrayRef Args, bool HadMultipleCandidates, bool ListInitialization, + bool StdInitListInitialization, bool ZeroInitialization, ConstructionKind ConstructKind, SourceRange ParenOrBraceRange); @@ -1137,6 +1140,13 @@ public: bool isListInitialization() const { return ListInitialization; } void setListInitialization(bool V) { ListInitialization = V; } + /// \brief Whether this constructor call was written as list-initialization, + /// but was interpreted as forming a std::initializer_list from the list + /// and passing that as a single constructor argument. + /// See C++11 [over.match.list]p1 bullet 1. + bool isStdInitListInitialization() const { return StdInitListInitialization; } + void setStdInitListInitialization(bool V) { StdInitListInitialization = V; } + /// \brief Whether this construction first requires /// zero-initialization before the initializer is called. bool requiresZeroInitialization() const { return ZeroInitialization; } @@ -1272,6 +1282,7 @@ public: SourceRange ParenOrBraceRange, bool HadMultipleCandidates, bool ListInitialization, + bool StdInitListInitialization, bool ZeroInitialization); explicit CXXTemporaryObjectExpr(EmptyShell Empty) : CXXConstructExpr(CXXTemporaryObjectExprClass, Empty), Type() { } diff --git a/include/clang/Sema/Initialization.h b/include/clang/Sema/Initialization.h index 76644250a5..4465850799 100644 --- a/include/clang/Sema/Initialization.h +++ b/include/clang/Sema/Initialization.h @@ -671,8 +671,6 @@ public: SK_ConversionSequenceNoNarrowing, /// \brief Perform list-initialization without a constructor. SK_ListInitialization, - /// \brief Perform list-initialization with an initializer list 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. @@ -705,6 +703,9 @@ public: SK_ProduceObjCObject, /// \brief Construct a std::initializer_list from an initializer list. SK_StdInitializerList, + /// \brief Perform initialization via a constructor taking a single + /// std::initializer_list argument. + SK_StdInitializerListConstructorCall, /// \brief Initialize an OpenCL sampler from an integer. SK_OCLSamplerInit, /// \brief Passing zero to a function where OpenCL event_t is expected. diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 8ff4ec02b1..b8b9eaf970 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -3858,16 +3858,18 @@ public: BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, CXXConstructorDecl *Constructor, MultiExprArg Exprs, bool HadMultipleCandidates, bool IsListInitialization, + bool IsStdInitListInitialization, bool RequiresZeroInit, unsigned ConstructKind, SourceRange ParenRange); - // FIXME: Can re remove this and have the above BuildCXXConstructExpr check if + // FIXME: Can we remove this and have the above BuildCXXConstructExpr check if // the constructor can be elidable? ExprResult BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, CXXConstructorDecl *Constructor, bool Elidable, MultiExprArg Exprs, bool HadMultipleCandidates, - bool IsListInitialization, bool RequiresZeroInit, + bool IsListInitialization, + bool IsStdInitListInitialization, bool RequiresZeroInit, unsigned ConstructKind, SourceRange ParenRange); /// BuildCXXDefaultArgExpr - Creates a CXXDefaultArgExpr, instantiating diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp index 54b043c3d5..64c21dd5c4 100644 --- a/lib/AST/ExprCXX.cpp +++ b/lib/AST/ExprCXX.cpp @@ -806,13 +806,16 @@ CXXTemporaryObjectExpr::CXXTemporaryObjectExpr(const ASTContext &C, SourceRange ParenOrBraceRange, bool HadMultipleCandidates, bool ListInitialization, + bool StdInitListInitialization, bool ZeroInitialization) : CXXConstructExpr(C, CXXTemporaryObjectExprClass, Type->getType().getNonReferenceType(), Type->getTypeLoc().getBeginLoc(), Cons, false, Args, HadMultipleCandidates, - ListInitialization, ZeroInitialization, + ListInitialization, + StdInitListInitialization, + ZeroInitialization, CXXConstructExpr::CK_Complete, ParenOrBraceRange), Type(Type) { } @@ -834,12 +837,14 @@ CXXConstructExpr *CXXConstructExpr::Create(const ASTContext &C, QualType T, ArrayRef Args, bool HadMultipleCandidates, bool ListInitialization, + bool StdInitListInitialization, bool ZeroInitialization, ConstructionKind ConstructKind, SourceRange ParenOrBraceRange) { return new (C) CXXConstructExpr(C, CXXConstructExprClass, T, Loc, D, Elidable, Args, HadMultipleCandidates, ListInitialization, + StdInitListInitialization, ZeroInitialization, ConstructKind, ParenOrBraceRange); } @@ -850,6 +855,7 @@ CXXConstructExpr::CXXConstructExpr(const ASTContext &C, StmtClass SC, ArrayRef args, bool HadMultipleCandidates, bool ListInitialization, + bool StdInitListInitialization, bool ZeroInitialization, ConstructionKind ConstructKind, SourceRange ParenOrBraceRange) @@ -861,6 +867,7 @@ CXXConstructExpr::CXXConstructExpr(const ASTContext &C, StmtClass SC, NumArgs(args.size()), Elidable(elidable), HadMultipleCandidates(HadMultipleCandidates), ListInitialization(ListInitialization), + StdInitListInitialization(StdInitListInitialization), ZeroInitialization(ZeroInitialization), ConstructKind(ConstructKind), Args(nullptr) { diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp index 8c54bba4c7..8ca80808e0 100644 --- a/lib/CodeGen/CGObjC.cpp +++ b/lib/CodeGen/CGObjC.cpp @@ -3021,6 +3021,7 @@ CodeGenFunction::GenerateObjCAtomicGetterCopyHelperFunction( ConstructorArgs, CXXConstExpr->hadMultipleCandidates(), CXXConstExpr->isListInitialization(), + CXXConstExpr->isStdInitListInitialization(), CXXConstExpr->requiresZeroInitialization(), CXXConstExpr->getConstructionKind(), SourceRange()); diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 281241ba75..14be51111d 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -10709,6 +10709,7 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, MultiExprArg ExprArgs, bool HadMultipleCandidates, bool IsListInitialization, + bool IsStdInitListInitialization, bool RequiresZeroInit, unsigned ConstructKind, SourceRange ParenRange) { @@ -10732,7 +10733,8 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, return BuildCXXConstructExpr(ConstructLoc, DeclInitType, Constructor, Elidable, ExprArgs, HadMultipleCandidates, - IsListInitialization, RequiresZeroInit, + IsListInitialization, + IsStdInitListInitialization, RequiresZeroInit, ConstructKind, ParenRange); } @@ -10744,13 +10746,15 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, MultiExprArg ExprArgs, bool HadMultipleCandidates, bool IsListInitialization, + bool IsStdInitListInitialization, bool RequiresZeroInit, unsigned ConstructKind, SourceRange ParenRange) { MarkFunctionReferenced(ConstructLoc, Constructor); return CXXConstructExpr::Create( Context, DeclInitType, ConstructLoc, Constructor, Elidable, ExprArgs, - HadMultipleCandidates, IsListInitialization, RequiresZeroInit, + HadMultipleCandidates, IsListInitialization, IsStdInitListInitialization, + RequiresZeroInit, static_cast(ConstructKind), ParenRange); } diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index fc3ede0994..7fe5e7a4bf 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -2560,11 +2560,11 @@ static ExprResult BuildCXXCastArgument(Sema &S, InitializedEntity::InitializeTemporary(Ty), Constructor->getAccess()); - ExprResult Result - = S.BuildCXXConstructExpr(CastLoc, Ty, cast(Method), - ConstructorArgs, HadMultipleCandidates, - /*ListInit*/ false, /*ZeroInit*/ false, - CXXConstructExpr::CK_Complete, SourceRange()); + ExprResult Result = S.BuildCXXConstructExpr( + CastLoc, Ty, cast(Method), + ConstructorArgs, HadMultipleCandidates, + /*ListInit*/ false, /*StdInitListInit*/ false, /*ZeroInit*/ false, + CXXConstructExpr::CK_Complete, SourceRange()); if (Result.isInvalid()) return ExprError(); @@ -2709,20 +2709,17 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, From, /*FIXME:ConstructLoc*/SourceLocation(), ConstructorArgs)) return ExprError(); - return BuildCXXConstructExpr(/*FIXME:ConstructLoc*/SourceLocation(), - ToType, SCS.CopyConstructor, - ConstructorArgs, - /*HadMultipleCandidates*/ false, - /*ListInit*/ false, /*ZeroInit*/ false, - CXXConstructExpr::CK_Complete, - SourceRange()); + return BuildCXXConstructExpr( + /*FIXME:ConstructLoc*/ SourceLocation(), ToType, SCS.CopyConstructor, + ConstructorArgs, /*HadMultipleCandidates*/ false, + /*ListInit*/ false, /*StdInitListInit*/ false, /*ZeroInit*/ false, + CXXConstructExpr::CK_Complete, SourceRange()); } - return BuildCXXConstructExpr(/*FIXME:ConstructLoc*/SourceLocation(), - ToType, SCS.CopyConstructor, - From, /*HadMultipleCandidates*/ false, - /*ListInit*/ false, /*ZeroInit*/ false, - CXXConstructExpr::CK_Complete, - SourceRange()); + return BuildCXXConstructExpr( + /*FIXME:ConstructLoc*/ SourceLocation(), ToType, SCS.CopyConstructor, + From, /*HadMultipleCandidates*/ false, + /*ListInit*/ false, /*StdInitListInit*/ false, /*ZeroInit*/ false, + CXXConstructExpr::CK_Complete, SourceRange()); } // Resolve overloaded function references. diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index f6d0b80f5c..4b756064ad 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -2760,7 +2760,6 @@ void InitializationSequence::Step::Destroy() { case SK_QualificationConversionLValue: case SK_LValueToRValue: case SK_ListInitialization: - case SK_ListConstructorCall: case SK_UnwrapInitList: case SK_RewrapInitList: case SK_ConstructorInitialization: @@ -2775,6 +2774,7 @@ void InitializationSequence::Step::Destroy() { case SK_PassByIndirectRestore: case SK_ProduceObjCObject: case SK_StdInitializerList: + case SK_StdInitializerListConstructorCall: case SK_OCLSamplerInit: case SK_OCLZeroEvent: break; @@ -2945,7 +2945,7 @@ InitializationSequence bool HadMultipleCandidates, bool FromInitList, bool AsInitList) { Step S; - S.Kind = FromInitList ? AsInitList ? SK_ListConstructorCall + S.Kind = FromInitList ? AsInitList ? SK_StdInitializerListConstructorCall : SK_ConstructorInitializationFromList : SK_ConstructorInitialization; S.Type = T; @@ -5148,6 +5148,7 @@ static ExprResult CopyObject(Sema &S, ConstructorArgs, HadMultipleCandidates, /*ListInit*/ false, + /*StdInitListInit*/ false, /*ZeroInit*/ false, CXXConstructExpr::CK_Complete, SourceRange()); @@ -5269,6 +5270,7 @@ PerformConstructorInitialization(Sema &S, const InitializationSequence::Step& Step, bool &ConstructorInitRequiresZeroInit, bool IsListInitialization, + bool IsStdInitListInitialization, SourceLocation LBraceLoc, SourceLocation RBraceLoc) { unsigned NumArgs = Args.size(); @@ -5330,7 +5332,7 @@ PerformConstructorInitialization(Sema &S, CurInit = new (S.Context) CXXTemporaryObjectExpr( S.Context, Constructor, TSInfo, ConstructorArgs, ParenOrBraceRange, HadMultipleCandidates, IsListInitialization, - ConstructorInitRequiresZeroInit); + IsStdInitListInitialization, ConstructorInitRequiresZeroInit); } else { CXXConstructExpr::ConstructionKind ConstructKind = CXXConstructExpr::CK_Complete; @@ -5359,6 +5361,7 @@ PerformConstructorInitialization(Sema &S, ConstructorArgs, HadMultipleCandidates, IsListInitialization, + IsStdInitListInitialization, ConstructorInitRequiresZeroInit, ConstructKind, ParenOrBraceRange); @@ -5368,6 +5371,7 @@ PerformConstructorInitialization(Sema &S, ConstructorArgs, HadMultipleCandidates, IsListInitialization, + IsStdInitListInitialization, ConstructorInitRequiresZeroInit, ConstructKind, ParenOrBraceRange); @@ -5784,7 +5788,7 @@ InitializationSequence::Perform(Sema &S, case SK_ConstructorInitialization: case SK_ConstructorInitializationFromList: - case SK_ListConstructorCall: + case SK_StdInitializerListConstructorCall: case SK_ZeroInitialization: break; } @@ -5959,6 +5963,7 @@ InitializationSequence::Perform(Sema &S, ConstructorArgs, HadMultipleCandidates, /*ListInit*/ false, + /*StdInitListInit*/ false, /*ZeroInit*/ false, CXXConstructExpr::CK_Complete, SourceRange()); @@ -6132,6 +6137,7 @@ InitializationSequence::Perform(Sema &S, Kind, Arg, *Step, ConstructorInitRequiresZeroInit, /*IsListInitialization*/true, + /*IsStdInitListInit*/false, InitList->getLBraceLoc(), InitList->getRBraceLoc()); break; @@ -6154,7 +6160,7 @@ InitializationSequence::Perform(Sema &S, } case SK_ConstructorInitialization: - case SK_ListConstructorCall: { + case SK_StdInitializerListConstructorCall: { // When an initializer list is passed for a parameter of type "reference // to object", we don't get an EK_Temporary entity, but instead an // EK_Parameter entity with reference type. @@ -6164,10 +6170,13 @@ InitializationSequence::Perform(Sema &S, InitializedEntity TempEntity = InitializedEntity::InitializeTemporary( Entity.getType().getNonReferenceType()); bool UseTemporary = Entity.getType()->isReferenceType(); + bool IsStdInitListInit = + Step->Kind == SK_StdInitializerListConstructorCall; CurInit = PerformConstructorInitialization( S, UseTemporary ? TempEntity : Entity, Kind, Args, *Step, ConstructorInitRequiresZeroInit, - /*IsListInitialization*/Step->Kind == SK_ListConstructorCall, + /*IsListInitialization*/IsStdInitListInit, + /*IsStdInitListInitialization*/IsStdInitListInit, /*LBraceLoc*/SourceLocation(), /*RBraceLoc*/SourceLocation()); break; @@ -7030,10 +7039,6 @@ void InitializationSequence::dump(raw_ostream &OS) const { OS << "list initialization via constructor"; break; - case SK_ListConstructorCall: - OS << "list initialization via initializer list constructor"; - break; - case SK_ZeroInitialization: OS << "zero initialization"; break; @@ -7074,6 +7079,10 @@ void InitializationSequence::dump(raw_ostream &OS) const { OS << "std::initializer_list from initializer list"; break; + case SK_StdInitializerListConstructorCall: + OS << "list initialization from std::initializer_list"; + break; + case SK_OCLSamplerInit: OS << "OpenCL sampler_t from integer constant"; break; diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index dc0b5c288c..1a71c0a4a5 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -2375,6 +2375,7 @@ public: MultiExprArg Args, bool HadMultipleCandidates, bool ListInitialization, + bool StdInitListInitialization, bool RequiresZeroInit, CXXConstructExpr::ConstructionKind ConstructKind, SourceRange ParenRange) { @@ -2387,6 +2388,7 @@ public: ConvertedArgs, HadMultipleCandidates, ListInitialization, + StdInitListInitialization, RequiresZeroInit, ConstructKind, ParenRange); } @@ -2877,6 +2879,11 @@ ExprResult TreeTransform::TransformInitializer(Expr *Init, if (!Construct || isa(Construct)) return getDerived().TransformExpr(Init); + // If the initialization implicitly converted an initializer list to a + // std::initializer_list object, unwrap the std::initializer_list too. + if (Construct && Construct->isStdInitListInitialization()) + return TransformInitializer(Construct->getArg(0), CXXDirectInit); + SmallVector NewArgs; bool ArgChanged = false; if (getDerived().TransformExprs(Construct->getArgs(), Construct->getNumArgs(), @@ -8571,6 +8578,7 @@ TreeTransform::TransformCXXConstructExpr(CXXConstructExpr *E) { Args, E->hadMultipleCandidates(), E->isListInitialization(), + E->isStdInitListInitialization(), E->requiresZeroInitialization(), E->getConstructionKind(), E->getParenOrBraceRange()); diff --git a/lib/Serialization/ASTReaderStmt.cpp b/lib/Serialization/ASTReaderStmt.cpp index 8239f4761c..29f0555b5f 100644 --- a/lib/Serialization/ASTReaderStmt.cpp +++ b/lib/Serialization/ASTReaderStmt.cpp @@ -1196,6 +1196,7 @@ void ASTStmtReader::VisitCXXConstructExpr(CXXConstructExpr *E) { E->setElidable(Record[Idx++]); E->setHadMultipleCandidates(Record[Idx++]); E->setListInitialization(Record[Idx++]); + E->setStdInitListInitialization(Record[Idx++]); E->setRequiresZeroInitialization(Record[Idx++]); E->setConstructionKind((CXXConstructExpr::ConstructionKind)Record[Idx++]); E->ParenOrBraceRange = ReadSourceRange(Record, Idx); diff --git a/lib/Serialization/ASTWriterStmt.cpp b/lib/Serialization/ASTWriterStmt.cpp index 30ee76934e..044ceb7914 100644 --- a/lib/Serialization/ASTWriterStmt.cpp +++ b/lib/Serialization/ASTWriterStmt.cpp @@ -1150,6 +1150,7 @@ void ASTStmtWriter::VisitCXXConstructExpr(CXXConstructExpr *E) { Record.push_back(E->isElidable()); Record.push_back(E->hadMultipleCandidates()); Record.push_back(E->isListInitialization()); + Record.push_back(E->isStdInitListInitialization()); Record.push_back(E->requiresZeroInitialization()); Record.push_back(E->getConstructionKind()); // FIXME: stable encoding Writer.AddSourceRange(E->getParenOrBraceRange(), Record); diff --git a/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp b/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp index eda4e44b77..70f7c642a5 100644 --- a/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp +++ b/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp @@ -242,6 +242,7 @@ namespace DR1070 { namespace ListInitInstantiate { struct A { A(std::initializer_list); + A(std::initializer_list); }; struct B : A { B(int); @@ -253,4 +254,8 @@ namespace ListInitInstantiate { template X::X() : a{B{0}, B{1}} {} X x; + + int f(const A&); + template void g() { int k = f({0}); } + template void g(); }