forked from OSchip/llvm-project
Implement DR990 and DR1070. Aggregate initialization initializes uninitialized
elements from {}, rather than value-initializing them. This permits calling an initializer-list constructor or constructing a std::initializer_list object. (It would also permit initializing a const reference or rvalue reference if that weren't explicitly prohibited by other rules.) llvm-svn: 210091
This commit is contained in:
parent
f051496804
commit
454a7cdfb3
|
@ -3909,6 +3909,7 @@ public:
|
|||
|
||||
// Iterators
|
||||
child_range children() {
|
||||
// FIXME: This does not include the array filler expression.
|
||||
if (InitExprs.empty()) return child_range();
|
||||
return child_range(&InitExprs[0], &InitExprs[0] + InitExprs.size());
|
||||
}
|
||||
|
|
|
@ -401,6 +401,13 @@ public:
|
|||
return SourceLocation::getFromRawEncoding(LocAndNRVO.Location);
|
||||
}
|
||||
|
||||
/// \brief If this is an array, vector, or complex number element, get the
|
||||
/// element's index.
|
||||
unsigned getElementIndex() const {
|
||||
assert(getKind() == EK_ArrayElement || getKind() == EK_VectorElement ||
|
||||
getKind() == EK_ComplexElement);
|
||||
return Index;
|
||||
}
|
||||
/// \brief If this is already the initializer for an array or vector
|
||||
/// element, sets the element index.
|
||||
void setElementIndex(unsigned Index) {
|
||||
|
@ -851,17 +858,17 @@ public:
|
|||
///
|
||||
/// \param Args the argument(s) provided for initialization.
|
||||
///
|
||||
/// \param InInitList true if we are initializing from an expression within
|
||||
/// an initializer list. This disallows narrowing conversions in C++11
|
||||
/// onwards.
|
||||
/// \param TopLevelOfInitList true if we are initializing from an expression
|
||||
/// at the top level inside an initializer list. This disallows
|
||||
/// narrowing conversions in C++11 onwards.
|
||||
InitializationSequence(Sema &S,
|
||||
const InitializedEntity &Entity,
|
||||
const InitializationKind &Kind,
|
||||
MultiExprArg Args,
|
||||
bool InInitList = false);
|
||||
bool TopLevelOfInitList = false);
|
||||
void InitializeFrom(Sema &S, const InitializedEntity &Entity,
|
||||
const InitializationKind &Kind, MultiExprArg Args,
|
||||
bool InInitList);
|
||||
bool TopLevelOfInitList);
|
||||
|
||||
~InitializationSequence();
|
||||
|
||||
|
|
|
@ -858,9 +858,21 @@ CodeGenFunction::EmitNewArrayInitializer(const CXXNewExpr *E,
|
|||
return true;
|
||||
};
|
||||
|
||||
// If all elements have already been initialized, skip any further
|
||||
// initialization.
|
||||
llvm::ConstantInt *ConstNum = dyn_cast<llvm::ConstantInt>(NumElements);
|
||||
if (ConstNum && ConstNum->getZExtValue() <= InitListElements) {
|
||||
// If there was a Cleanup, deactivate it.
|
||||
if (CleanupDominator)
|
||||
DeactivateCleanupBlock(Cleanup, CleanupDominator);
|
||||
return;
|
||||
}
|
||||
|
||||
assert(Init && "have trailing elements to initialize but no initializer");
|
||||
|
||||
// If this is a constructor call, try to optimize it out, and failing that
|
||||
// emit a single loop to initialize all remaining elements.
|
||||
if (const CXXConstructExpr *CCE = dyn_cast_or_null<CXXConstructExpr>(Init)){
|
||||
if (const CXXConstructExpr *CCE = dyn_cast<CXXConstructExpr>(Init)) {
|
||||
CXXConstructorDecl *Ctor = CCE->getConstructor();
|
||||
if (Ctor->isTrivial()) {
|
||||
// If new expression did not specify value-initialization, then there
|
||||
|
@ -891,7 +903,7 @@ CodeGenFunction::EmitNewArrayInitializer(const CXXNewExpr *E,
|
|||
|
||||
// If this is value-initialization, we can usually use memset.
|
||||
ImplicitValueInitExpr IVIE(ElementType);
|
||||
if (Init && isa<ImplicitValueInitExpr>(Init)) {
|
||||
if (isa<ImplicitValueInitExpr>(Init)) {
|
||||
if (TryMemsetInitialization())
|
||||
return;
|
||||
|
||||
|
@ -906,15 +918,10 @@ CodeGenFunction::EmitNewArrayInitializer(const CXXNewExpr *E,
|
|||
assert(getContext().hasSameUnqualifiedType(ElementType, Init->getType()) &&
|
||||
"got wrong type of element to initialize");
|
||||
|
||||
llvm::ConstantInt *ConstNum = dyn_cast<llvm::ConstantInt>(NumElements);
|
||||
|
||||
// If all elements have already been initialized, skip the whole loop.
|
||||
if (ConstNum && ConstNum->getZExtValue() <= InitListElements) {
|
||||
// If there was a Cleanup, deactivate it.
|
||||
if (CleanupDominator)
|
||||
DeactivateCleanupBlock(Cleanup, CleanupDominator);
|
||||
return;
|
||||
}
|
||||
// If we have an empty initializer list, we can usually use memset.
|
||||
if (auto *ILE = dyn_cast<InitListExpr>(Init))
|
||||
if (ILE->getNumInits() == 0 && TryMemsetInitialization())
|
||||
return;
|
||||
|
||||
// Create the loop blocks.
|
||||
llvm::BasicBlock *EntryBB = Builder.GetInsertBlock();
|
||||
|
|
|
@ -312,15 +312,20 @@ class InitListChecker {
|
|||
int numArrayElements(QualType DeclType);
|
||||
int numStructUnionElements(QualType DeclType);
|
||||
|
||||
void FillInValueInitForField(unsigned Init, FieldDecl *Field,
|
||||
static ExprResult PerformEmptyInit(Sema &SemaRef,
|
||||
SourceLocation Loc,
|
||||
const InitializedEntity &Entity,
|
||||
bool VerifyOnly);
|
||||
void FillInEmptyInitForField(unsigned Init, FieldDecl *Field,
|
||||
const InitializedEntity &ParentEntity,
|
||||
InitListExpr *ILE, bool &RequiresSecondPass);
|
||||
void FillInValueInitializations(const InitializedEntity &Entity,
|
||||
void FillInEmptyInitializations(const InitializedEntity &Entity,
|
||||
InitListExpr *ILE, bool &RequiresSecondPass);
|
||||
bool CheckFlexibleArrayInit(const InitializedEntity &Entity,
|
||||
Expr *InitExpr, FieldDecl *Field,
|
||||
bool TopLevelObject);
|
||||
void CheckValueInitializable(const InitializedEntity &Entity);
|
||||
void CheckEmptyInitializable(const InitializedEntity &Entity,
|
||||
SourceLocation Loc);
|
||||
|
||||
public:
|
||||
InitListChecker(Sema &S, const InitializedEntity &Entity,
|
||||
|
@ -333,33 +338,84 @@ public:
|
|||
};
|
||||
} // end anonymous namespace
|
||||
|
||||
void InitListChecker::CheckValueInitializable(const InitializedEntity &Entity) {
|
||||
assert(VerifyOnly &&
|
||||
"CheckValueInitializable is only inteded for verification mode.");
|
||||
|
||||
SourceLocation Loc;
|
||||
ExprResult InitListChecker::PerformEmptyInit(Sema &SemaRef,
|
||||
SourceLocation Loc,
|
||||
const InitializedEntity &Entity,
|
||||
bool VerifyOnly) {
|
||||
InitializationKind Kind = InitializationKind::CreateValue(Loc, Loc, Loc,
|
||||
true);
|
||||
InitializationSequence InitSeq(SemaRef, Entity, Kind, None);
|
||||
if (InitSeq.Failed())
|
||||
MultiExprArg SubInit;
|
||||
Expr *InitExpr;
|
||||
InitListExpr DummyInitList(SemaRef.Context, Loc, None, Loc);
|
||||
|
||||
// C++ [dcl.init.aggr]p7:
|
||||
// If there are fewer initializer-clauses in the list than there are
|
||||
// members in the aggregate, then each member not explicitly initialized
|
||||
// ...
|
||||
if (SemaRef.getLangOpts().CPlusPlus11 &&
|
||||
Entity.getType()->getBaseElementTypeUnsafe()->isRecordType()) {
|
||||
// C++1y / DR1070:
|
||||
// shall be initialized [...] from an empty initializer list.
|
||||
//
|
||||
// We apply the resolution of this DR to C++11 but not C++98, since C++98
|
||||
// does not have useful semantics for initialization from an init list.
|
||||
// We treat this as copy-initialization, because aggregate initialization
|
||||
// always performs copy-initialization on its elements.
|
||||
//
|
||||
// Only do this if we're initializing a class type, to avoid filling in
|
||||
// the initializer list where possible.
|
||||
InitExpr = VerifyOnly ? &DummyInitList : new (SemaRef.Context)
|
||||
InitListExpr(SemaRef.Context, Loc, None, Loc);
|
||||
InitExpr->setType(SemaRef.Context.VoidTy);
|
||||
SubInit = InitExpr;
|
||||
Kind = InitializationKind::CreateCopy(Loc, Loc);
|
||||
} else {
|
||||
// C++03:
|
||||
// shall be value-initialized.
|
||||
}
|
||||
|
||||
InitializationSequence InitSeq(SemaRef, Entity, Kind, SubInit);
|
||||
if (!InitSeq) {
|
||||
if (!VerifyOnly) {
|
||||
InitSeq.Diagnose(SemaRef, Entity, Kind, SubInit);
|
||||
if (Entity.getKind() == InitializedEntity::EK_Member)
|
||||
SemaRef.Diag(Entity.getDecl()->getLocation(),
|
||||
diag::note_in_omitted_aggregate_initializer)
|
||||
<< /*field*/1 << Entity.getDecl();
|
||||
else if (Entity.getKind() == InitializedEntity::EK_ArrayElement)
|
||||
SemaRef.Diag(Loc, diag::note_in_omitted_aggregate_initializer)
|
||||
<< /*array element*/0 << Entity.getElementIndex();
|
||||
}
|
||||
return ExprError();
|
||||
}
|
||||
|
||||
return VerifyOnly ? ExprResult(static_cast<Expr *>(nullptr))
|
||||
: InitSeq.Perform(SemaRef, Entity, Kind, SubInit);
|
||||
}
|
||||
|
||||
void InitListChecker::CheckEmptyInitializable(const InitializedEntity &Entity,
|
||||
SourceLocation Loc) {
|
||||
assert(VerifyOnly &&
|
||||
"CheckEmptyInitializable is only inteded for verification mode.");
|
||||
if (PerformEmptyInit(SemaRef, Loc, Entity, /*VerifyOnly*/true).isInvalid())
|
||||
hadError = true;
|
||||
}
|
||||
|
||||
void InitListChecker::FillInValueInitForField(unsigned Init, FieldDecl *Field,
|
||||
void InitListChecker::FillInEmptyInitForField(unsigned Init, FieldDecl *Field,
|
||||
const InitializedEntity &ParentEntity,
|
||||
InitListExpr *ILE,
|
||||
bool &RequiresSecondPass) {
|
||||
SourceLocation Loc = ILE->getLocStart();
|
||||
SourceLocation Loc = ILE->getLocEnd();
|
||||
unsigned NumInits = ILE->getNumInits();
|
||||
InitializedEntity MemberEntity
|
||||
= InitializedEntity::InitializeMember(Field, &ParentEntity);
|
||||
if (Init >= NumInits || !ILE->getInit(Init)) {
|
||||
// If there's no explicit initializer but we have a default initializer, use
|
||||
// that. This only happens in C++1y, since classes with default
|
||||
// initializers are not aggregates in C++11.
|
||||
// C++1y [dcl.init.aggr]p7:
|
||||
// If there are fewer initializer-clauses in the list than there are
|
||||
// members in the aggregate, then each member not explicitly initialized
|
||||
// shall be initialized from its brace-or-equal-initializer [...]
|
||||
if (Field->hasInClassInitializer()) {
|
||||
Expr *DIE = CXXDefaultInitExpr::Create(SemaRef.Context,
|
||||
ILE->getRBraceLoc(), Field);
|
||||
Expr *DIE = CXXDefaultInitExpr::Create(SemaRef.Context, Loc, Field);
|
||||
if (Init < NumInits)
|
||||
ILE->setInit(Init, DIE);
|
||||
else {
|
||||
|
@ -369,9 +425,6 @@ void InitListChecker::FillInValueInitForField(unsigned Init, FieldDecl *Field,
|
|||
return;
|
||||
}
|
||||
|
||||
// FIXME: We probably don't need to handle references
|
||||
// specially here, since value-initialization of references is
|
||||
// handled in InitializationSequence.
|
||||
if (Field->getType()->isReferenceType()) {
|
||||
// C++ [dcl.init.aggr]p9:
|
||||
// If an incomplete or empty initializer-list leaves a
|
||||
|
@ -386,20 +439,8 @@ void InitListChecker::FillInValueInitForField(unsigned Init, FieldDecl *Field,
|
|||
return;
|
||||
}
|
||||
|
||||
InitializationKind Kind = InitializationKind::CreateValue(Loc, Loc, Loc,
|
||||
true);
|
||||
InitializationSequence InitSeq(SemaRef, MemberEntity, Kind, None);
|
||||
if (!InitSeq) {
|
||||
InitSeq.Diagnose(SemaRef, MemberEntity, Kind, None);
|
||||
SemaRef.Diag(Field->getLocation(),
|
||||
diag::note_in_omitted_aggregate_initializer)
|
||||
<< /*field*/1 << Field;
|
||||
hadError = true;
|
||||
return;
|
||||
}
|
||||
|
||||
ExprResult MemberInit
|
||||
= InitSeq.Perform(SemaRef, MemberEntity, Kind, None);
|
||||
ExprResult MemberInit = PerformEmptyInit(SemaRef, Loc, MemberEntity,
|
||||
/*VerifyOnly*/false);
|
||||
if (MemberInit.isInvalid()) {
|
||||
hadError = true;
|
||||
return;
|
||||
|
@ -409,8 +450,8 @@ void InitListChecker::FillInValueInitForField(unsigned Init, FieldDecl *Field,
|
|||
// Do nothing
|
||||
} else if (Init < NumInits) {
|
||||
ILE->setInit(Init, MemberInit.getAs<Expr>());
|
||||
} else if (InitSeq.isConstructorInitialization()) {
|
||||
// Value-initialization requires a constructor call, so
|
||||
} else if (!isa<ImplicitValueInitExpr>(MemberInit.get())) {
|
||||
// Empty initialization requires a constructor call, so
|
||||
// extend the initializer list to include the constructor
|
||||
// call and make a note that we'll need to take another pass
|
||||
// through the initializer list.
|
||||
|
@ -419,7 +460,7 @@ void InitListChecker::FillInValueInitForField(unsigned Init, FieldDecl *Field,
|
|||
}
|
||||
} else if (InitListExpr *InnerILE
|
||||
= dyn_cast<InitListExpr>(ILE->getInit(Init)))
|
||||
FillInValueInitializations(MemberEntity, InnerILE,
|
||||
FillInEmptyInitializations(MemberEntity, InnerILE,
|
||||
RequiresSecondPass);
|
||||
}
|
||||
|
||||
|
@ -427,7 +468,7 @@ void InitListChecker::FillInValueInitForField(unsigned Init, FieldDecl *Field,
|
|||
/// with expressions that perform value-initialization of the
|
||||
/// appropriate type.
|
||||
void
|
||||
InitListChecker::FillInValueInitializations(const InitializedEntity &Entity,
|
||||
InitListChecker::FillInEmptyInitializations(const InitializedEntity &Entity,
|
||||
InitListExpr *ILE,
|
||||
bool &RequiresSecondPass) {
|
||||
assert((ILE->getType() != SemaRef.Context.VoidTy) &&
|
||||
|
@ -436,13 +477,13 @@ InitListChecker::FillInValueInitializations(const InitializedEntity &Entity,
|
|||
if (const RecordType *RType = ILE->getType()->getAs<RecordType>()) {
|
||||
const RecordDecl *RDecl = RType->getDecl();
|
||||
if (RDecl->isUnion() && ILE->getInitializedFieldInUnion())
|
||||
FillInValueInitForField(0, ILE->getInitializedFieldInUnion(),
|
||||
FillInEmptyInitForField(0, ILE->getInitializedFieldInUnion(),
|
||||
Entity, ILE, RequiresSecondPass);
|
||||
else if (RDecl->isUnion() && isa<CXXRecordDecl>(RDecl) &&
|
||||
cast<CXXRecordDecl>(RDecl)->hasInClassInitializer()) {
|
||||
for (auto *Field : RDecl->fields()) {
|
||||
if (Field->hasInClassInitializer()) {
|
||||
FillInValueInitForField(0, Field, Entity, ILE, RequiresSecondPass);
|
||||
FillInEmptyInitForField(0, Field, Entity, ILE, RequiresSecondPass);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -455,7 +496,7 @@ InitListChecker::FillInValueInitializations(const InitializedEntity &Entity,
|
|||
if (hadError)
|
||||
return;
|
||||
|
||||
FillInValueInitForField(Init, Field, Entity, ILE, RequiresSecondPass);
|
||||
FillInEmptyInitForField(Init, Field, Entity, ILE, RequiresSecondPass);
|
||||
if (hadError)
|
||||
return;
|
||||
|
||||
|
@ -489,10 +530,6 @@ InitListChecker::FillInValueInitializations(const InitializedEntity &Entity,
|
|||
} else
|
||||
ElementType = ILE->getType();
|
||||
|
||||
SourceLocation Loc = ILE->getLocEnd();
|
||||
if (ILE->getSyntacticForm())
|
||||
Loc = ILE->getSyntacticForm()->getLocEnd();
|
||||
|
||||
for (unsigned Init = 0; Init != NumElements; ++Init) {
|
||||
if (hadError)
|
||||
return;
|
||||
|
@ -503,19 +540,9 @@ InitListChecker::FillInValueInitializations(const InitializedEntity &Entity,
|
|||
|
||||
Expr *InitExpr = (Init < NumInits ? ILE->getInit(Init) : nullptr);
|
||||
if (!InitExpr && !ILE->hasArrayFiller()) {
|
||||
InitializationKind Kind = InitializationKind::CreateValue(Loc, Loc, Loc,
|
||||
true);
|
||||
InitializationSequence InitSeq(SemaRef, ElementEntity, Kind, None);
|
||||
if (!InitSeq) {
|
||||
InitSeq.Diagnose(SemaRef, ElementEntity, Kind, None);
|
||||
SemaRef.Diag(Loc, diag::note_in_omitted_aggregate_initializer)
|
||||
<< /*array element*/0 << Init;
|
||||
hadError = true;
|
||||
return;
|
||||
}
|
||||
|
||||
ExprResult ElementInit
|
||||
= InitSeq.Perform(SemaRef, ElementEntity, Kind, None);
|
||||
ExprResult ElementInit = PerformEmptyInit(SemaRef, ILE->getLocEnd(),
|
||||
ElementEntity,
|
||||
/*VerifyOnly*/false);
|
||||
if (ElementInit.isInvalid()) {
|
||||
hadError = true;
|
||||
return;
|
||||
|
@ -538,8 +565,8 @@ InitListChecker::FillInValueInitializations(const InitializedEntity &Entity,
|
|||
return;
|
||||
}
|
||||
|
||||
if (InitSeq.isConstructorInitialization()) {
|
||||
// Value-initialization requires a constructor call, so
|
||||
if (!isa<ImplicitValueInitExpr>(ElementInit.get())) {
|
||||
// Empty initialization requires a constructor call, so
|
||||
// extend the initializer list to include the constructor
|
||||
// call and make a note that we'll need to take another pass
|
||||
// through the initializer list.
|
||||
|
@ -549,7 +576,7 @@ InitListChecker::FillInValueInitializations(const InitializedEntity &Entity,
|
|||
}
|
||||
} else if (InitListExpr *InnerILE
|
||||
= dyn_cast_or_null<InitListExpr>(InitExpr))
|
||||
FillInValueInitializations(ElementEntity, InnerILE, RequiresSecondPass);
|
||||
FillInEmptyInitializations(ElementEntity, InnerILE, RequiresSecondPass);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -567,9 +594,9 @@ InitListChecker::InitListChecker(Sema &S, const InitializedEntity &Entity,
|
|||
|
||||
if (!hadError && !VerifyOnly) {
|
||||
bool RequiresSecondPass = false;
|
||||
FillInValueInitializations(Entity, FullyStructuredList, RequiresSecondPass);
|
||||
FillInEmptyInitializations(Entity, FullyStructuredList, RequiresSecondPass);
|
||||
if (RequiresSecondPass && !hadError)
|
||||
FillInValueInitializations(Entity, FullyStructuredList,
|
||||
FillInEmptyInitializations(Entity, FullyStructuredList,
|
||||
RequiresSecondPass);
|
||||
}
|
||||
}
|
||||
|
@ -678,7 +705,6 @@ void InitListChecker::CheckExplicitInitList(const InitializedEntity &Entity,
|
|||
InitListExpr *IList, QualType &T,
|
||||
InitListExpr *StructuredList,
|
||||
bool TopLevelObject) {
|
||||
assert(IList->isExplicit() && "Illegal Implicit InitListExpr");
|
||||
if (!VerifyOnly) {
|
||||
SyntacticToSemantic[IList] = StructuredList;
|
||||
StructuredList->setSyntacticForm(IList);
|
||||
|
@ -1121,8 +1147,9 @@ void InitListChecker::CheckVectorType(const InitializedEntity &Entity,
|
|||
if (Index >= IList->getNumInits()) {
|
||||
// Make sure the element type can be value-initialized.
|
||||
if (VerifyOnly)
|
||||
CheckValueInitializable(
|
||||
InitializedEntity::InitializeElement(SemaRef.Context, 0, Entity));
|
||||
CheckEmptyInitializable(
|
||||
InitializedEntity::InitializeElement(SemaRef.Context, 0, Entity),
|
||||
IList->getLocEnd());
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1169,7 +1196,7 @@ void InitListChecker::CheckVectorType(const InitializedEntity &Entity,
|
|||
// Don't attempt to go past the end of the init list
|
||||
if (Index >= IList->getNumInits()) {
|
||||
if (VerifyOnly)
|
||||
CheckValueInitializable(ElementEntity);
|
||||
CheckEmptyInitializable(ElementEntity, IList->getLocEnd());
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1346,8 +1373,9 @@ void InitListChecker::CheckArrayType(const InitializedEntity &Entity,
|
|||
// If so, check if doing that is possible.
|
||||
// FIXME: This needs to detect holes left by designated initializers too.
|
||||
if (maxElementsKnown && elementIndex < maxElements)
|
||||
CheckValueInitializable(InitializedEntity::InitializeElement(
|
||||
SemaRef.Context, 0, Entity));
|
||||
CheckEmptyInitializable(InitializedEntity::InitializeElement(
|
||||
SemaRef.Context, 0, Entity),
|
||||
IList->getLocEnd());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1432,8 +1460,9 @@ void InitListChecker::CheckStructUnionTypes(const InitializedEntity &Entity,
|
|||
Field != FieldEnd; ++Field) {
|
||||
if (Field->getDeclName()) {
|
||||
if (VerifyOnly)
|
||||
CheckValueInitializable(
|
||||
InitializedEntity::InitializeMember(*Field, &Entity));
|
||||
CheckEmptyInitializable(
|
||||
InitializedEntity::InitializeMember(*Field, &Entity),
|
||||
IList->getLocEnd());
|
||||
else
|
||||
StructuredList->setInitializedFieldInUnion(*Field);
|
||||
break;
|
||||
|
@ -1545,8 +1574,9 @@ void InitListChecker::CheckStructUnionTypes(const InitializedEntity &Entity,
|
|||
// FIXME: Should check for holes left by designated initializers too.
|
||||
for (; Field != FieldEnd && !hadError; ++Field) {
|
||||
if (!Field->isUnnamedBitfield() && !Field->hasInClassInitializer())
|
||||
CheckValueInitializable(
|
||||
InitializedEntity::InitializeMember(*Field, &Entity));
|
||||
CheckEmptyInitializable(
|
||||
InitializedEntity::InitializeMember(*Field, &Entity),
|
||||
IList->getLocEnd());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
// RUN: %clang_cc1 -std=c++98 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
|
||||
// RUN: %clang_cc1 -std=c++11 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
|
||||
// RUN: %clang_cc1 -std=c++1y %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
|
||||
|
||||
// expected-no-diagnostics
|
||||
|
||||
namespace std {
|
||||
__extension__ typedef __SIZE_TYPE__ size_t;
|
||||
|
||||
template<typename T> struct initializer_list {
|
||||
const T *p; size_t n;
|
||||
initializer_list(const T *p, size_t n);
|
||||
};
|
||||
}
|
||||
|
||||
namespace dr1070 { // dr1070: 3.5
|
||||
#if __cplusplus >= 201103L
|
||||
struct A {
|
||||
A(std::initializer_list<int>);
|
||||
};
|
||||
struct B {
|
||||
int i;
|
||||
A a;
|
||||
};
|
||||
B b = {1};
|
||||
struct C {
|
||||
std::initializer_list<int> a;
|
||||
B b;
|
||||
std::initializer_list<double> c;
|
||||
};
|
||||
C c = {};
|
||||
#endif
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
// RUN: %clang_cc1 -std=c++98 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
|
||||
// RUN: %clang_cc1 -std=c++11 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
|
||||
// RUN: %clang_cc1 -std=c++1y %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
|
||||
|
||||
#if __cplusplus < 201103L
|
||||
// expected-no-diagnostics
|
||||
#endif
|
||||
|
||||
namespace std {
|
||||
__extension__ typedef __SIZE_TYPE__ size_t;
|
||||
|
||||
template<typename T> struct initializer_list {
|
||||
const T *p; size_t n;
|
||||
initializer_list(const T *p, size_t n);
|
||||
};
|
||||
}
|
||||
|
||||
namespace dr990 { // dr990: 3.5
|
||||
#if __cplusplus >= 201103L
|
||||
struct A { // expected-note 2{{candidate}}
|
||||
A(std::initializer_list<int>); // expected-note {{candidate}}
|
||||
};
|
||||
struct B {
|
||||
A a;
|
||||
};
|
||||
B b1 { };
|
||||
B b2 { 1 }; // expected-error {{no viable conversion from 'int' to 'dr990::A'}}
|
||||
B b3 { { 1 } };
|
||||
|
||||
struct C {
|
||||
C();
|
||||
C(int);
|
||||
C(std::initializer_list<int>) = delete; // expected-note {{here}}
|
||||
};
|
||||
C c1[3] { 1 }; // ok
|
||||
C c2[3] { 1, {2} }; // expected-error {{call to deleted}}
|
||||
|
||||
struct D {
|
||||
D();
|
||||
D(std::initializer_list<int>);
|
||||
D(std::initializer_list<double>);
|
||||
};
|
||||
D d{};
|
||||
#endif
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
// RUN: %clang_cc1 -std=c++11 -S -triple x86_64-none-linux-gnu -emit-llvm -o - %s | FileCheck %s
|
||||
// RUN: %clang_cc1 -std=c++11 -triple x86_64-none-linux-gnu -emit-llvm -o - %s | FileCheck %s
|
||||
|
||||
namespace std {
|
||||
typedef decltype(sizeof(int)) size_t;
|
||||
|
@ -431,3 +431,20 @@ namespace nested {
|
|||
// CHECK: }
|
||||
}
|
||||
}
|
||||
|
||||
namespace DR1070 {
|
||||
struct A {
|
||||
A(std::initializer_list<int>);
|
||||
};
|
||||
struct B {
|
||||
int i;
|
||||
A a;
|
||||
};
|
||||
B b = {1};
|
||||
struct C {
|
||||
std::initializer_list<int> a;
|
||||
B b;
|
||||
std::initializer_list<double> c;
|
||||
};
|
||||
C c = {};
|
||||
}
|
||||
|
|
|
@ -46,7 +46,7 @@ B z { 1 };
|
|||
// CHECK: store i8 %{{.*}}, i8* getelementptr inbounds ({{.*}} @a, i32 0, i32 2)
|
||||
// CHECK: call i32 @_ZN1A1fEv({{.*}} @a)
|
||||
// CHECK: store i32 %{{.*}}, i32* getelementptr inbounds ({{.*}}* @a, i32 0, i32 3)
|
||||
// CHECK: call void @{{.*}}C1Ev({{.*}} getelementptr inbounds (%struct.A* @a, i32 0, i32 4))
|
||||
// CHECK: store double 1.000000e+00, double* getelementptr inbounds ({{.*}} @a, i32 0, i32 4, i32 0)
|
||||
|
||||
// No dynamic initialization of 'b':
|
||||
|
||||
|
|
|
@ -389,8 +389,8 @@ namespace PR11410 {
|
|||
|
||||
struct B {
|
||||
A a; // expected-note {{in implicit initialization of field 'a'}}
|
||||
} b = { // expected-error {{call to deleted constructor}}
|
||||
};
|
||||
} b = {
|
||||
}; // expected-error {{call to deleted constructor}}
|
||||
|
||||
struct C {
|
||||
C(int = 0); // expected-note 2{{candidate}}
|
||||
|
|
|
@ -230,3 +230,11 @@ namespace PR18013 {
|
|||
int f();
|
||||
std::initializer_list<long (*)()> x = {f}; // expected-error {{cannot initialize an array element of type 'long (*const)()' with an lvalue of type 'int ()': different return type ('long' vs 'int')}}
|
||||
}
|
||||
|
||||
namespace DR1070 {
|
||||
struct S {
|
||||
S(std::initializer_list<int>);
|
||||
};
|
||||
S s[3] = { {1, 2, 3}, {4, 5} }; // ok
|
||||
S *p = new S[3] { {1, 2, 3}, {4, 5} }; // ok
|
||||
}
|
||||
|
|
|
@ -3233,7 +3233,7 @@ of class templates</td>
|
|||
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#532">532</a></td>
|
||||
<td>C++11</td>
|
||||
<td>Member/nonmember operator template partial ordering</td>
|
||||
<td class="none" align="center">Unknown</td>
|
||||
<td class="svn" align="center">SVN</td>
|
||||
</tr>
|
||||
<tr id="533">
|
||||
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#533">533</a></td>
|
||||
|
@ -5755,7 +5755,7 @@ and <I>POD class</I></td>
|
|||
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#990">990</a></td>
|
||||
<td>CD2</td>
|
||||
<td>Value initialization with multiple initializer-list constructors</td>
|
||||
<td class="none" align="center">Unknown</td>
|
||||
<td class="svn" align="center">SVN</td>
|
||||
</tr>
|
||||
<tr id="991">
|
||||
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#991">991</a></td>
|
||||
|
@ -6235,7 +6235,7 @@ and <I>POD class</I></td>
|
|||
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1070">1070</a></td>
|
||||
<td>C++11</td>
|
||||
<td>Missing initializer clauses in aggregate initialization</td>
|
||||
<td class="none" align="center">Unknown</td>
|
||||
<td class="svn" align="center">SVN</td>
|
||||
</tr>
|
||||
<tr id="1071">
|
||||
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1071">1071</a></td>
|
||||
|
|
Loading…
Reference in New Issue