Index: include/clang/AST/ExprCXX.h =================================================================== --- include/clang/AST/ExprCXX.h +++ include/clang/AST/ExprCXX.h @@ -1504,6 +1504,9 @@ SourceLocation getRParenLoc() const { return RParenLoc; } void setRParenLoc(SourceLocation L) { RParenLoc = L; } + /// Determine whether this expression models list-initialization. + bool isListInitialization() const { return LParenLoc.isInvalid(); } + SourceLocation getLocStart() const LLVM_READONLY; SourceLocation getLocEnd() const LLVM_READONLY; Index: include/clang/Sema/Initialization.h =================================================================== --- include/clang/Sema/Initialization.h +++ include/clang/Sema/Initialization.h @@ -539,8 +539,15 @@ } static InitializationKind CreateDirectList(SourceLocation InitLoc) { - return InitializationKind(IK_DirectList, IC_Normal, - InitLoc, InitLoc, InitLoc); + return InitializationKind(IK_DirectList, IC_Normal, InitLoc, InitLoc, + InitLoc); + } + + static InitializationKind CreateDirectList(SourceLocation InitLoc, + SourceLocation LBraceLoc, + SourceLocation RBraceLoc) { + return InitializationKind(IK_DirectList, IC_Normal, InitLoc, LBraceLoc, + RBraceLoc); } /// \brief Create a direct initialization due to a cast that isn't a C-style @@ -598,7 +605,8 @@ Expr *Init) { if (!Init) return CreateDefault(Loc); if (!DirectInit) return CreateCopy(Loc, Init->getLocStart()); - if (isa(Init)) return CreateDirectList(Loc); + if (isa(Init)) + return CreateDirectList(Loc, Init->getLocStart(), Init->getLocEnd()); return CreateDirect(Loc, Init->getLocStart(), Init->getLocEnd()); } @@ -660,12 +668,20 @@ bool allowExplicitConversionFunctionsInRefBinding() const { return !isCopyInit() || Context == IC_ExplicitConvs; } + + /// Determine whether this initialization has a source range containing the + /// locations of open and closing parentheses or braces. + bool hasParenOrBraceRange() const { + return Kind == IK_Direct || Kind == IK_Value || Kind == IK_DirectList; + } /// \brief Retrieve the source range containing the locations of the open - /// and closing parentheses for value and direct initializations. - SourceRange getParenRange() const { - assert((Kind == IK_Direct || Kind == IK_Value) && - "Only direct- and value-initialization have parentheses"); + /// and closing parentheses or braces for value, direct, and direct list + /// initializations. + SourceRange getParenOrBraceRange() const { + assert(hasParenOrBraceRange() && "Only direct, value, and direct-list " + "initialization have parentheses or " + "braces"); return SourceRange(Locations[1], Locations[2]); } }; Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -5106,14 +5106,16 @@ /// or class type construction ("ClassType(x,y,z)") /// or creation of a value-initialized type ("int()"). ExprResult ActOnCXXTypeConstructExpr(ParsedType TypeRep, - SourceLocation LParenLoc, + SourceLocation LParenOrBraceLoc, MultiExprArg Exprs, - SourceLocation RParenLoc); + SourceLocation RParenOrBraceLoc, + bool ListInitialization); ExprResult BuildCXXTypeConstructExpr(TypeSourceInfo *Type, SourceLocation LParenLoc, MultiExprArg Exprs, - SourceLocation RParenLoc); + SourceLocation RParenLoc, + bool ListInitialization); /// ActOnCXXNew - Parsed a C++ 'new' expression. ExprResult ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal, Index: lib/CodeGen/CoverageMappingGen.cpp =================================================================== --- lib/CodeGen/CoverageMappingGen.cpp +++ lib/CodeGen/CoverageMappingGen.cpp @@ -74,7 +74,10 @@ bool hasEndLoc() const { return LocEnd.hasValue(); } - void setEndLoc(SourceLocation Loc) { LocEnd = Loc; } + void setEndLoc(SourceLocation Loc) { + assert(Loc.isValid() && "Setting an invalid end location"); + LocEnd = Loc; + } SourceLocation getEndLoc() const { assert(LocEnd && "Region has no end location"); Index: lib/Parse/ParseExprCXX.cpp =================================================================== --- lib/Parse/ParseExprCXX.cpp +++ lib/Parse/ParseExprCXX.cpp @@ -1672,9 +1672,9 @@ if (Init.isInvalid()) return Init; Expr *InitList = Init.get(); - return Actions.ActOnCXXTypeConstructExpr(TypeRep, SourceLocation(), - MultiExprArg(&InitList, 1), - SourceLocation()); + return Actions.ActOnCXXTypeConstructExpr( + TypeRep, InitList->getLocStart(), MultiExprArg(&InitList, 1), + InitList->getLocEnd(), /*ListInitialization=*/true); } else { BalancedDelimiterTracker T(*this, tok::l_paren); T.consumeOpen(); @@ -1702,9 +1702,9 @@ assert((Exprs.size() == 0 || Exprs.size()-1 == CommaLocs.size())&& "Unexpected number of commas!"); - return Actions.ActOnCXXTypeConstructExpr(TypeRep, T.getOpenLocation(), - Exprs, - T.getCloseLocation()); + return Actions.ActOnCXXTypeConstructExpr(TypeRep, T.getOpenLocation(), + Exprs, T.getCloseLocation(), + /*ListInitialization=*/false); } } Index: lib/Sema/SemaDeclCXX.cpp =================================================================== --- lib/Sema/SemaDeclCXX.cpp +++ lib/Sema/SemaDeclCXX.cpp @@ -3589,9 +3589,12 @@ ExprResult Init = InitExpr; if (!FD->getType()->isDependentType() && !InitExpr->isTypeDependent()) { InitializedEntity Entity = InitializedEntity::InitializeMember(FD); - InitializationKind Kind = FD->getInClassInitStyle() == ICIS_ListInit - ? InitializationKind::CreateDirectList(InitExpr->getLocStart()) - : InitializationKind::CreateCopy(InitExpr->getLocStart(), InitLoc); + InitializationKind Kind = + FD->getInClassInitStyle() == ICIS_ListInit + ? InitializationKind::CreateDirectList(InitExpr->getLocStart(), + InitExpr->getLocStart(), + InitExpr->getLocEnd()) + : InitializationKind::CreateCopy(InitExpr->getLocStart(), InitLoc); InitializationSequence Seq(*this, Entity, Kind, InitExpr); Init = Seq.Perform(*this, Entity, Kind, InitExpr); if (Init.isInvalid()) { @@ -3986,9 +3989,10 @@ : InitializedEntity::InitializeMember(IndirectMember, nullptr); InitializationKind Kind = - InitList ? InitializationKind::CreateDirectList(IdLoc) - : InitializationKind::CreateDirect(IdLoc, InitRange.getBegin(), - InitRange.getEnd()); + InitList ? InitializationKind::CreateDirectList( + IdLoc, Init->getLocStart(), Init->getLocEnd()) + : InitializationKind::CreateDirect(IdLoc, InitRange.getBegin(), + InitRange.getEnd()); InitializationSequence InitSeq(*this, MemberEntity, Kind, Args); ExprResult MemberInit = InitSeq.Perform(*this, MemberEntity, Kind, Args, @@ -4040,9 +4044,10 @@ InitializedEntity DelegationEntity = InitializedEntity::InitializeDelegation( QualType(ClassDecl->getTypeForDecl(), 0)); InitializationKind Kind = - InitList ? InitializationKind::CreateDirectList(NameLoc) - : InitializationKind::CreateDirect(NameLoc, InitRange.getBegin(), - InitRange.getEnd()); + InitList ? InitializationKind::CreateDirectList( + NameLoc, Init->getLocStart(), Init->getLocEnd()) + : InitializationKind::CreateDirect(NameLoc, InitRange.getBegin(), + InitRange.getEnd()); InitializationSequence InitSeq(*this, DelegationEntity, Kind, Args); ExprResult DelegationInit = InitSeq.Perform(*this, DelegationEntity, Kind, Args, nullptr); @@ -4174,9 +4179,9 @@ InitializedEntity BaseEntity = InitializedEntity::InitializeBase(Context, BaseSpec, VirtualBaseSpec); InitializationKind Kind = - InitList ? InitializationKind::CreateDirectList(BaseLoc) - : InitializationKind::CreateDirect(BaseLoc, InitRange.getBegin(), - InitRange.getEnd()); + InitList ? InitializationKind::CreateDirectList(BaseLoc) + : InitializationKind::CreateDirect(BaseLoc, InitRange.getBegin(), + InitRange.getEnd()); InitializationSequence InitSeq(*this, BaseEntity, Kind, Args); ExprResult BaseInit = InitSeq.Perform(*this, BaseEntity, Kind, Args, nullptr); if (BaseInit.isInvalid()) Index: lib/Sema/SemaExpr.cpp =================================================================== --- lib/Sema/SemaExpr.cpp +++ lib/Sema/SemaExpr.cpp @@ -11601,8 +11601,8 @@ // C++11 5.17p9: // The meaning of x = {v} [...] is that of x = T(v) [...]. The meaning // of x = {} is x = T(). - InitializationKind Kind = - InitializationKind::CreateDirectList(RHSExpr->getLocStart()); + InitializationKind Kind = InitializationKind::CreateDirectList( + RHSExpr->getLocStart(), RHSExpr->getLocStart(), RHSExpr->getLocEnd()); InitializedEntity Entity = InitializedEntity::InitializeTemporary(LHSExpr->getType()); InitializationSequence InitSeq(*this, Entity, Kind, RHSExpr); Index: lib/Sema/SemaExprCXX.cpp =================================================================== --- lib/Sema/SemaExprCXX.cpp +++ lib/Sema/SemaExprCXX.cpp @@ -1244,11 +1244,16 @@ return Class && Class->isBeingDefined(); } +/// Parse construction of a specified type. +/// Can be interpreted either as function-style casting ("int(x)") +/// or class type construction ("ClassType(x,y,z)") +/// or creation of a value-initialized type ("int()"). ExprResult Sema::ActOnCXXTypeConstructExpr(ParsedType TypeRep, - SourceLocation LParenLoc, + SourceLocation LParenOrBraceLoc, MultiExprArg exprs, - SourceLocation RParenLoc) { + SourceLocation RParenOrBraceLoc, + bool ListInitialization) { if (!TypeRep) return ExprError(); @@ -1257,7 +1262,8 @@ if (!TInfo) TInfo = Context.getTrivialTypeSourceInfo(Ty, SourceLocation()); - auto Result = BuildCXXTypeConstructExpr(TInfo, LParenLoc, exprs, RParenLoc); + auto Result = BuildCXXTypeConstructExpr(TInfo, LParenOrBraceLoc, exprs, + RParenOrBraceLoc, ListInitialization); // Avoid creating a non-type-dependent expression that contains typos. // Non-type-dependent expressions are liable to be discarded without // checking for embedded typos. @@ -1267,38 +1273,40 @@ return Result; } -/// ActOnCXXTypeConstructExpr - Parse construction of a specified type. -/// Can be interpreted either as function-style casting ("int(x)") -/// or class type construction ("ClassType(x,y,z)") -/// or creation of a value-initialized type ("int()"). ExprResult Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo, - SourceLocation LParenLoc, + SourceLocation LParenOrBraceLoc, MultiExprArg Exprs, - SourceLocation RParenLoc) { + SourceLocation RParenOrBraceLoc, + bool ListInitialization) { QualType Ty = TInfo->getType(); SourceLocation TyBeginLoc = TInfo->getTypeLoc().getBeginLoc(); if (Ty->isDependentType() || CallExpr::hasAnyTypeDependentArguments(Exprs)) { - return CXXUnresolvedConstructExpr::Create(Context, TInfo, LParenLoc, Exprs, - RParenLoc); + // FIXME: CXXUnresolvedConstructExpr does not model list-initialization + // directly. We work around this by dropping the locations of the braces. + SourceRange Locs = ListInitialization + ? SourceRange() + : SourceRange(LParenOrBraceLoc, RParenOrBraceLoc); + return CXXUnresolvedConstructExpr::Create(Context, TInfo, Locs.getBegin(), + Exprs, Locs.getEnd()); } - bool ListInitialization = LParenLoc.isInvalid(); assert((!ListInitialization || (Exprs.size() == 1 && isa(Exprs[0]))) && "List initialization must have initializer list as expression."); - SourceRange FullRange = SourceRange(TyBeginLoc, - ListInitialization ? Exprs[0]->getSourceRange().getEnd() : RParenLoc); + SourceRange FullRange = SourceRange(TyBeginLoc, RParenOrBraceLoc); InitializedEntity Entity = InitializedEntity::InitializeTemporary(TInfo); InitializationKind Kind = Exprs.size() ? ListInitialization - ? InitializationKind::CreateDirectList(TyBeginLoc) - : InitializationKind::CreateDirect(TyBeginLoc, LParenLoc, - RParenLoc) - : InitializationKind::CreateValue(TyBeginLoc, LParenLoc, RParenLoc); + ? InitializationKind::CreateDirectList( + TyBeginLoc, LParenOrBraceLoc, RParenOrBraceLoc) + : InitializationKind::CreateDirect(TyBeginLoc, LParenOrBraceLoc, + RParenOrBraceLoc) + : InitializationKind::CreateValue(TyBeginLoc, LParenOrBraceLoc, + RParenOrBraceLoc); // C++1z [expr.type.conv]p1: // If the type is a placeholder for a deduced class type, [...perform class @@ -1319,7 +1327,8 @@ if (Exprs.size() == 1 && !ListInitialization && !isa(Exprs[0])) { Expr *Arg = Exprs[0]; - return BuildCXXFunctionalCastExpr(TInfo, Ty, LParenLoc, Arg, RParenLoc); + return BuildCXXFunctionalCastExpr(TInfo, Ty, LParenOrBraceLoc, Arg, + RParenOrBraceLoc); } // For an expression of the form T(), T shall not be an array type. @@ -1367,9 +1376,12 @@ // CXXTemporaryObjectExpr. It's also weird that the functional cast // is sometimes handled by initialization and sometimes not. QualType ResultType = Result.get()->getType(); + SourceRange Locs = ListInitialization + ? SourceRange() + : SourceRange(LParenOrBraceLoc, RParenOrBraceLoc); Result = CXXFunctionalCastExpr::Create( - Context, ResultType, Expr::getValueKindForType(Ty), TInfo, - CK_NoOp, Result.get(), /*Path=*/nullptr, LParenLoc, RParenLoc); + Context, ResultType, Expr::getValueKindForType(Ty), TInfo, CK_NoOp, + Result.get(), /*Path=*/nullptr, Locs.getBegin(), Locs.getEnd()); } return Result; @@ -1728,7 +1740,9 @@ // - Otherwise, the new-initializer is interpreted according to the // initialization rules of 8.5 for direct-initialization. : initStyle == CXXNewExpr::ListInit - ? InitializationKind::CreateDirectList(TypeRange.getBegin()) + ? InitializationKind::CreateDirectList(TypeRange.getBegin(), + Initializer->getLocStart(), + Initializer->getLocEnd()) : InitializationKind::CreateDirect(TypeRange.getBegin(), DirectInitRange.getBegin(), DirectInitRange.getEnd()); Index: lib/Sema/SemaInit.cpp =================================================================== --- lib/Sema/SemaInit.cpp +++ lib/Sema/SemaInit.cpp @@ -3533,8 +3533,8 @@ clang::ArrayType::Normal, 0); InitializedEntity HiddenArray = InitializedEntity::InitializeTemporary(ArrayType); - InitializationKind Kind = - InitializationKind::CreateDirectList(List->getExprLoc()); + InitializationKind Kind = InitializationKind::CreateDirectList( + List->getExprLoc(), List->getLocStart(), List->getLocEnd()); TryListInitialization(S, HiddenArray, Kind, List, Sequence, TreatUnavailableAsInvalid); if (Sequence) @@ -6031,10 +6031,7 @@ TypeSourceInfo *TSInfo = Entity.getTypeSourceInfo(); if (!TSInfo) TSInfo = S.Context.getTrivialTypeSourceInfo(Entity.getType(), Loc); - SourceRange ParenOrBraceRange = - (Kind.getKind() == InitializationKind::IK_DirectList) - ? SourceRange(LBraceLoc, RBraceLoc) - : Kind.getParenRange(); + SourceRange ParenOrBraceRange = Kind.getParenOrBraceRange(); if (auto *Shadow = dyn_cast( Step.Function.FoundDecl.getDecl())) { @@ -6068,7 +6065,7 @@ if (IsListInitialization) ParenOrBraceRange = SourceRange(LBraceLoc, RBraceLoc); else if (Kind.getKind() == InitializationKind::IK_Direct) - ParenOrBraceRange = Kind.getParenRange(); + ParenOrBraceRange = Kind.getParenOrBraceRange(); // If the entity allows NRVO, mark the construction as elidable // unconditionally. @@ -6594,7 +6591,7 @@ if (Kind.getKind() == InitializationKind::IK_Direct && !Kind.isExplicitCast()) { // Rebuild the ParenListExpr. - SourceRange ParenRange = Kind.getParenRange(); + SourceRange ParenRange = Kind.getParenOrBraceRange(); return S.ActOnParenListExpr(ParenRange.getBegin(), ParenRange.getEnd(), Args); } @@ -7114,14 +7111,17 @@ bool IsStdInitListInit = Step->Kind == SK_StdInitializerListConstructorCall; Expr *Source = CurInit.get(); + SourceRange Range = Kind.hasParenOrBraceRange() + ? Kind.getParenOrBraceRange() + : SourceRange(); CurInit = PerformConstructorInitialization( S, UseTemporary ? TempEntity : Entity, Kind, Source ? MultiExprArg(Source) : Args, *Step, ConstructorInitRequiresZeroInit, /*IsListInitialization*/ IsStdInitListInit, /*IsStdInitListInitialization*/ IsStdInitListInit, - /*LBraceLoc*/ SourceLocation(), - /*RBraceLoc*/ SourceLocation()); + /*LBraceLoc*/ Range.getBegin(), + /*RBraceLoc*/ Range.getEnd()); break; } Index: lib/Sema/TreeTransform.h =================================================================== --- lib/Sema/TreeTransform.h +++ lib/Sema/TreeTransform.h @@ -2581,10 +2581,11 @@ ExprResult RebuildCXXFunctionalCastExpr(TypeSourceInfo *TInfo, SourceLocation LParenLoc, Expr *Sub, - SourceLocation RParenLoc) { + SourceLocation RParenLoc, + bool ListInitialization) { return getSema().BuildCXXTypeConstructExpr(TInfo, LParenLoc, - MultiExprArg(&Sub, 1), - RParenLoc); + MultiExprArg(&Sub, 1), RParenLoc, + ListInitialization); } /// \brief Build a new C++ typeid(type) expression. @@ -2684,8 +2685,8 @@ ExprResult RebuildCXXScalarValueInitExpr(TypeSourceInfo *TSInfo, SourceLocation LParenLoc, SourceLocation RParenLoc) { - return getSema().BuildCXXTypeConstructExpr(TSInfo, LParenLoc, - None, RParenLoc); + return getSema().BuildCXXTypeConstructExpr( + TSInfo, LParenLoc, None, RParenLoc, /*ListInitialization=*/false); } /// \brief Build a new C++ "new" expression. @@ -2842,13 +2843,12 @@ /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. ExprResult RebuildCXXTemporaryObjectExpr(TypeSourceInfo *TSInfo, - SourceLocation LParenLoc, + SourceLocation LParenOrBraceLoc, MultiExprArg Args, - SourceLocation RParenLoc) { - return getSema().BuildCXXTypeConstructExpr(TSInfo, - LParenLoc, - Args, - RParenLoc); + SourceLocation RParenOrBraceLoc, + bool ListInitialization) { + return getSema().BuildCXXTypeConstructExpr( + TSInfo, LParenOrBraceLoc, Args, RParenOrBraceLoc, ListInitialization); } /// \brief Build a new object-construction expression. @@ -2858,11 +2858,10 @@ ExprResult RebuildCXXUnresolvedConstructExpr(TypeSourceInfo *TSInfo, SourceLocation LParenLoc, MultiExprArg Args, - SourceLocation RParenLoc) { - return getSema().BuildCXXTypeConstructExpr(TSInfo, - LParenLoc, - Args, - RParenLoc); + SourceLocation RParenLoc, + bool ListInitialization) { + return getSema().BuildCXXTypeConstructExpr(TSInfo, LParenLoc, Args, + RParenLoc, ListInitialization); } /// \brief Build a new member reference expression. @@ -9936,7 +9935,8 @@ return getDerived().RebuildCXXFunctionalCastExpr(Type, E->getLParenLoc(), SubExpr.get(), - E->getRParenLoc()); + E->getRParenLoc(), + E->isListInitialization()); } template @@ -10852,11 +10852,12 @@ return SemaRef.MaybeBindToTemporary(E); } - // FIXME: Pass in E->isListInitialization(). - return getDerived().RebuildCXXTemporaryObjectExpr(T, - /*FIXME:*/T->getTypeLoc().getEndLoc(), - Args, - E->getLocEnd()); + // FIXME: We should just pass E->isListInitialization(), but we're not + // prepared to handle list-initialization without a child InitListExpr. + SourceLocation LParenLoc = T->getTypeLoc().getEndLoc(); + return getDerived().RebuildCXXTemporaryObjectExpr( + T, LParenLoc, Args, E->getLocEnd(), + /*ListInitialization=*/LParenLoc.isInvalid()); } template @@ -11142,10 +11143,8 @@ return E; // FIXME: we're faking the locations of the commas - return getDerived().RebuildCXXUnresolvedConstructExpr(T, - E->getLParenLoc(), - Args, - E->getRParenLoc()); + return getDerived().RebuildCXXUnresolvedConstructExpr( + T, E->getLParenLoc(), Args, E->getRParenLoc(), E->isListInitialization()); } template Index: test/CoverageMapping/classtemplate.cpp =================================================================== --- test/CoverageMapping/classtemplate.cpp +++ test/CoverageMapping/classtemplate.cpp @@ -2,6 +2,7 @@ // RUN: FileCheck -input-file %tmapping %s --check-prefix=CHECK-CONSTRUCTOR // RUN: FileCheck -input-file %tmapping %s --check-prefix=CHECK-GETTER // RUN: FileCheck -input-file %tmapping %s --check-prefix=CHECK-SETTER +// RUN: FileCheck -input-file %tmapping %s --check-prefix=CHECK-INIT-LIST template class Test { @@ -44,11 +45,51 @@ void unmangleable(UninstantiatedClassWithTraits x) {} }; +void abort() __attribute__((noreturn)); + +namespace std { +typedef decltype(sizeof(int)) size_t; + +template struct initializer_list { + const E *p; + size_t n; + initializer_list(const E *p, size_t n) : p(p), n(n) {} +}; + +template struct pair { + F f; + S s; + pair(const F &f, const S &s) : f(f), s(s) {} +}; + +struct string { + const char *str; + string() { abort(); } + string(const char *S) : str(S) {} + ~string() { abort(); } +}; + +template +struct map { + using T = pair; + map(initializer_list i, const string &s = string()) {} + ~map() { abort(); } +}; + +}; // namespace std + +// CHECK-INIT-LIST-LABEL: _Z5Test4v: +std::map Test4() { // CHECK-INIT-LIST: File 0, [[@LINE]]:28 -> [[@LINE+3]]:2 = #0 + abort(); + return std::map{{0, 0}}; // CHECK-INIT-LIST-NEXT: [[@LINE]]:3 -> [[@LINE]]:36 = 0 +} + int main() { Test t; t.set(Test::A, 5.5); t.set(Test::T, 5.6); t.set(Test::G, 5.7); t.set(Test::C, 5.8); + Test4(); return 0; } Index: test/SemaCXX/sourceranges.cpp =================================================================== --- test/SemaCXX/sourceranges.cpp +++ test/SemaCXX/sourceranges.cpp @@ -1,4 +1,5 @@ // RUN: %clang_cc1 -triple i686-mingw32 -ast-dump %s | FileCheck %s +// RUN: %clang_cc1 -triple i686-mingw32 -std=c++1z -ast-dump %s | FileCheck %s -check-prefix=CHECK-1Z template class P { @@ -12,7 +13,7 @@ typedef int C; } -// CHECK: VarDecl {{0x[0-9a-fA-F]+}} col:15 ImplicitConstrArray 'foo::A [2]' +// CHECK: VarDecl {{0x[0-9a-fA-F]+}} col:15 ImplicitConstrArray 'foo::A [2]' static foo::A ImplicitConstrArray[2]; int main() { @@ -50,3 +51,89 @@ D d = D(12); // CHECK: CXXConstructExpr {{0x[0-9a-fA-F]+}} 'D' 'void (int){{( __attribute__\(\(thiscall\)\))?}}' } + +void abort() __attribute__((noreturn)); + +namespace std { +typedef decltype(sizeof(int)) size_t; + +template struct initializer_list { + const E *p; + size_t n; + initializer_list(const E *p, size_t n) : p(p), n(n) {} +}; + +template struct pair { + F f; + S s; + pair(const F &f, const S &s) : f(f), s(s) {} +}; + +struct string { + const char *str; + string() { abort(); } + string(const char *S) : str(S) {} + ~string() { abort(); } +}; + +template +struct map { + using T = pair; + map(initializer_list i, const string &s = string()) {} + ~map() { abort(); } +}; + +}; // namespace std + +#if __cplusplus >= 201703L +// CHECK-1Z: FunctionDecl {{.*}} construct_with_init_list +std::map construct_with_init_list() { + // CHECK-1Z-NEXT: CompoundStmt + // CHECK-1Z-NEXT: ReturnStmt {{.*}} {{0, 0}}; +} + +// CHECK-1Z: NamespaceDecl {{.*}} in_class_init +namespace in_class_init { + struct A {}; + + // CHECK-1Z: CXXRecordDecl {{.*}} struct B definition + struct B { + // CHECK-1Z: FieldDecl {{.*}} a 'in_class_init::A' + // CHECK-1Z-NEXT: InitListExpr {{.*}}