[Parse] Forward brace locations to TypeConstructExpr

When parsing C++ type construction expressions with list initialization,
forward the locations of the braces to Sema.

Without these locations, the code coverage pass crashes on the given test
case, because the pass relies on getLocEnd() returning a valid location.

Here is what this patch does in more detail:

  - Forwards init-list brace locations to Sema (ParseExprCXX),
  - Builds an InitializationKind with these locations (SemaExprCXX), and
  - Uses these locations for constructor initialization (SemaInit).

The remaining changes fall out of introducing a new overload for
creating direct-list InitializationKinds.

Testing: check-clang, and a stage2 coverage-enabled build of clang with
asserts enabled.

Differential Revision: https://reviews.llvm.org/D41921

llvm-svn: 322729
This commit is contained in:
Vedant Kumar 2018-01-17 18:53:51 +00:00
parent cc9fd4b661
commit a14a1f923f
12 changed files with 260 additions and 90 deletions

View File

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

View File

@ -539,8 +539,15 @@ public:
}
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 @@ public:
Expr *Init) {
if (!Init) return CreateDefault(Loc);
if (!DirectInit) return CreateCopy(Loc, Init->getLocStart());
if (isa<InitListExpr>(Init)) return CreateDirectList(Loc);
if (isa<InitListExpr>(Init))
return CreateDirectList(Loc, Init->getLocStart(), Init->getLocEnd());
return CreateDirect(Loc, Init->getLocStart(), Init->getLocEnd());
}
@ -661,11 +669,19 @@ public:
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]);
}
};

View File

@ -5106,14 +5106,16 @@ public:
/// 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,

View File

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

View File

@ -1672,9 +1672,9 @@ Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) {
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();
@ -1703,8 +1703,8 @@ Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) {
assert((Exprs.size() == 0 || Exprs.size()-1 == CommaLocs.size())&&
"Unexpected number of commas!");
return Actions.ActOnCXXTypeConstructExpr(TypeRep, T.getOpenLocation(),
Exprs,
T.getCloseLocation());
Exprs, T.getCloseLocation(),
/*ListInitialization=*/false);
}
}

View File

@ -3589,8 +3589,11 @@ void Sema::ActOnFinishCXXInClassMemberInitializer(Decl *D,
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 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);
@ -3986,7 +3989,8 @@ Sema::BuildMemberInitializer(ValueDecl *Member, Expr *Init,
: InitializedEntity::InitializeMember(IndirectMember,
nullptr);
InitializationKind Kind =
InitList ? InitializationKind::CreateDirectList(IdLoc)
InitList ? InitializationKind::CreateDirectList(
IdLoc, Init->getLocStart(), Init->getLocEnd())
: InitializationKind::CreateDirect(IdLoc, InitRange.getBegin(),
InitRange.getEnd());
@ -4040,7 +4044,8 @@ Sema::BuildDelegatingInitializer(TypeSourceInfo *TInfo, Expr *Init,
InitializedEntity DelegationEntity = InitializedEntity::InitializeDelegation(
QualType(ClassDecl->getTypeForDecl(), 0));
InitializationKind Kind =
InitList ? InitializationKind::CreateDirectList(NameLoc)
InitList ? InitializationKind::CreateDirectList(
NameLoc, Init->getLocStart(), Init->getLocEnd())
: InitializationKind::CreateDirect(NameLoc, InitRange.getBegin(),
InitRange.getEnd());
InitializationSequence InitSeq(*this, DelegationEntity, Kind, Args);

View File

@ -11601,8 +11601,8 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
// 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);

View File

@ -1244,11 +1244,16 @@ bool Sema::isThisOutsideMemberFunctionBody(QualType BaseType) {
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 @@ Sema::ActOnCXXTypeConstructExpr(ParsedType TypeRep,
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 @@ Sema::ActOnCXXTypeConstructExpr(ParsedType TypeRep,
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<InitListExpr>(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 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo,
if (Exprs.size() == 1 && !ListInitialization &&
!isa<InitListExpr>(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 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo,
// 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 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
// - 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());

View File

@ -3533,8 +3533,8 @@ static bool TryInitializerListConstruction(Sema &S,
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 @@ PerformConstructorInitialization(Sema &S,
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<ConstructorUsingShadowDecl>(
Step.Function.FoundDecl.getDecl())) {
@ -6068,7 +6065,7 @@ PerformConstructorInitialization(Sema &S,
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 @@ InitializationSequence::Perform(Sema &S,
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 @@ InitializationSequence::Perform(Sema &S,
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;
}

View File

@ -2581,10 +2581,11 @@ public:
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 @@ public:
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 @@ public:
/// 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 @@ public:
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 @@ TreeTransform<Derived>::TransformCXXFunctionalCastExpr(
return getDerived().RebuildCXXFunctionalCastExpr(Type,
E->getLParenLoc(),
SubExpr.get(),
E->getRParenLoc());
E->getRParenLoc(),
E->isListInitialization());
}
template<typename Derived>
@ -10852,11 +10852,12 @@ TreeTransform<Derived>::TransformCXXTemporaryObjectExpr(
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<typename Derived>
@ -11142,10 +11143,8 @@ TreeTransform<Derived>::TransformCXXUnresolvedConstructExpr(
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<typename Derived>

View File

@ -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 TT>
class Test {
@ -44,11 +45,51 @@ template <class T> class Test3 {
void unmangleable(UninstantiatedClassWithTraits<T> x) {}
};
void abort() __attribute__((noreturn));
namespace std {
typedef decltype(sizeof(int)) size_t;
template <typename E> struct initializer_list {
const E *p;
size_t n;
initializer_list(const E *p, size_t n) : p(p), n(n) {}
};
template <typename F, typename S> 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<typename K, typename V>
struct map {
using T = pair<K, V>;
map(initializer_list<T> i, const string &s = string()) {}
~map() { abort(); }
};
}; // namespace std
// CHECK-INIT-LIST-LABEL: _Z5Test4v:
std::map<int, int> Test4() { // CHECK-INIT-LIST: File 0, [[@LINE]]:28 -> [[@LINE+3]]:2 = #0
abort();
return std::map<int, int>{{0, 0}}; // CHECK-INIT-LIST-NEXT: [[@LINE]]:3 -> [[@LINE]]:36 = 0
}
int main() {
Test<unsigned> t;
t.set(Test<unsigned>::A, 5.5);
t.set(Test<unsigned>::T, 5.6);
t.set(Test<unsigned>::G, 5.7);
t.set(Test<unsigned>::C, 5.8);
Test4();
return 0;
}

View File

@ -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 T>
class P {
@ -12,7 +13,7 @@ enum B {};
typedef int C;
}
// CHECK: VarDecl {{0x[0-9a-fA-F]+}} <line:16:1, col:36> col:15 ImplicitConstrArray 'foo::A [2]'
// CHECK: VarDecl {{0x[0-9a-fA-F]+}} <line:[[@LINE+1]]:1, col:36> col:15 ImplicitConstrArray 'foo::A [2]'
static foo::A ImplicitConstrArray[2];
int main() {
@ -50,3 +51,89 @@ void construct() {
D d = D(12);
// CHECK: CXXConstructExpr {{0x[0-9a-fA-F]+}} <col:9, col:13> 'D' 'void (int){{( __attribute__\(\(thiscall\)\))?}}'
}
void abort() __attribute__((noreturn));
namespace std {
typedef decltype(sizeof(int)) size_t;
template <typename E> struct initializer_list {
const E *p;
size_t n;
initializer_list(const E *p, size_t n) : p(p), n(n) {}
};
template <typename F, typename S> 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<typename K, typename V>
struct map {
using T = pair<K, V>;
map(initializer_list<T> i, const string &s = string()) {}
~map() { abort(); }
};
}; // namespace std
#if __cplusplus >= 201703L
// CHECK-1Z: FunctionDecl {{.*}} construct_with_init_list
std::map<int, int> construct_with_init_list() {
// CHECK-1Z-NEXT: CompoundStmt
// CHECK-1Z-NEXT: ReturnStmt {{.*}} <line:[[@LINE+5]]:3, col:35
// CHECK-1Z-NEXT: ExprWithCleanups {{.*}} <col:10, col:35
// CHECK-1Z-NEXT: CXXBindTemporaryExpr {{.*}} <col:10, col:35
// CHECK-1Z-NEXT: CXXTemporaryObjectExpr {{.*}} <col:10, col:35
// CHECK-1Z-NEXT: CXXStdInitializerListExpr {{.*}} <col:28, col:35
return std::map<int, int>{{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 {{.*}} <col:11, col:12
A a = {};
};
}
// CHECK-1Z: NamespaceDecl {{.*}} delegating_constructor_init
namespace delegating_constructor_init {
struct A {};
struct B : A {
A a;
B(A a) : a(a) {}
};
// CHECK-1Z: CXXRecordDecl {{.*}} struct C definition
struct C : B {
// CHECK-1Z: CXXConstructorDecl {{.*}} C
// CHECK-1Z-NEXT: CXXCtorInitializer 'delegating_constructor_init::B'
// CHECK-1Z-NEXT: CXXConstructExpr {{.*}} <col:11, col:15
// CHECK-1Z-NEXT: InitListExpr {{.*}} <col:13, col:14
C() : B({}) {};
};
}
// CHECK-1Z: NamespaceDecl {{.*}} new_init
namespace new_init {
void A() {
// CHECK-1Z: CXXNewExpr {{.*}} <line:[[@LINE+2]]:5, col:14
// CHECK-1Z-NEXT: InitListExpr {{.*}} <col:12, col:14
new int{0};
}
}
#endif