forked from OSchip/llvm-project
PR12670: Support for initializing an array of non-aggregate class type from an
initializer list. Patch by Olivier Goffart, with extra testcases by Meador Inge and Daniel Lunow. llvm-svn: 159896
This commit is contained in:
parent
4ff9ff974c
commit
e20c83d9ed
|
@ -687,22 +687,21 @@ void InitListChecker::CheckListElementTypes(const InitializedEntity &Entity,
|
|||
} else if (DeclType->isVectorType()) {
|
||||
CheckVectorType(Entity, IList, DeclType, Index,
|
||||
StructuredList, StructuredIndex);
|
||||
} else if (DeclType->isAggregateType()) {
|
||||
if (DeclType->isRecordType()) {
|
||||
RecordDecl *RD = DeclType->getAs<RecordType>()->getDecl();
|
||||
CheckStructUnionTypes(Entity, IList, DeclType, RD->field_begin(),
|
||||
SubobjectIsDesignatorContext, Index,
|
||||
StructuredList, StructuredIndex,
|
||||
TopLevelObject);
|
||||
} else if (DeclType->isArrayType()) {
|
||||
llvm::APSInt Zero(
|
||||
SemaRef.Context.getTypeSize(SemaRef.Context.getSizeType()),
|
||||
false);
|
||||
CheckArrayType(Entity, IList, DeclType, Zero,
|
||||
SubobjectIsDesignatorContext, Index,
|
||||
StructuredList, StructuredIndex);
|
||||
} else
|
||||
llvm_unreachable("Aggregate that isn't a structure or array?!");
|
||||
} else if (DeclType->isRecordType()) {
|
||||
assert(DeclType->isAggregateType() &&
|
||||
"non-aggregate records should be handed in CheckSubElementType");
|
||||
RecordDecl *RD = DeclType->getAs<RecordType>()->getDecl();
|
||||
CheckStructUnionTypes(Entity, IList, DeclType, RD->field_begin(),
|
||||
SubobjectIsDesignatorContext, Index,
|
||||
StructuredList, StructuredIndex,
|
||||
TopLevelObject);
|
||||
} else if (DeclType->isArrayType()) {
|
||||
llvm::APSInt Zero(
|
||||
SemaRef.Context.getTypeSize(SemaRef.Context.getSizeType()),
|
||||
false);
|
||||
CheckArrayType(Entity, IList, DeclType, Zero,
|
||||
SubobjectIsDesignatorContext, Index,
|
||||
StructuredList, StructuredIndex);
|
||||
} else if (DeclType->isVoidType() || DeclType->isFunctionType()) {
|
||||
// This type is invalid, issue a diagnostic.
|
||||
++Index;
|
||||
|
@ -710,19 +709,6 @@ void InitListChecker::CheckListElementTypes(const InitializedEntity &Entity,
|
|||
SemaRef.Diag(IList->getLocStart(), diag::err_illegal_initializer_type)
|
||||
<< DeclType;
|
||||
hadError = true;
|
||||
} else if (DeclType->isRecordType()) {
|
||||
// C++ [dcl.init]p14:
|
||||
// [...] If the class is an aggregate (8.5.1), and the initializer
|
||||
// is a brace-enclosed list, see 8.5.1.
|
||||
//
|
||||
// Note: 8.5.1 is handled below; here, we diagnose the case where
|
||||
// we have an initializer list and a destination type that is not
|
||||
// an aggregate.
|
||||
// FIXME: In C++0x, this is yet another form of initialization.
|
||||
if (!VerifyOnly)
|
||||
SemaRef.Diag(IList->getLocStart(), diag::err_init_non_aggr_init_list)
|
||||
<< DeclType << IList->getSourceRange();
|
||||
hadError = true;
|
||||
} else if (DeclType->isReferenceType()) {
|
||||
CheckReferenceType(Entity, IList, DeclType, Index,
|
||||
StructuredList, StructuredIndex);
|
||||
|
@ -747,18 +733,25 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity,
|
|||
unsigned &StructuredIndex) {
|
||||
Expr *expr = IList->getInit(Index);
|
||||
if (InitListExpr *SubInitList = dyn_cast<InitListExpr>(expr)) {
|
||||
unsigned newIndex = 0;
|
||||
unsigned newStructuredIndex = 0;
|
||||
InitListExpr *newStructuredList
|
||||
= getStructuredSubobjectInit(IList, Index, ElemType,
|
||||
StructuredList, StructuredIndex,
|
||||
SubInitList->getSourceRange());
|
||||
CheckExplicitInitList(Entity, SubInitList, ElemType, newIndex,
|
||||
newStructuredList, newStructuredIndex);
|
||||
++StructuredIndex;
|
||||
++Index;
|
||||
return;
|
||||
} else if (ElemType->isScalarType()) {
|
||||
if (!ElemType->isRecordType() || ElemType->isAggregateType()) {
|
||||
unsigned newIndex = 0;
|
||||
unsigned newStructuredIndex = 0;
|
||||
InitListExpr *newStructuredList
|
||||
= getStructuredSubobjectInit(IList, Index, ElemType,
|
||||
StructuredList, StructuredIndex,
|
||||
SubInitList->getSourceRange());
|
||||
CheckExplicitInitList(Entity, SubInitList, ElemType, newIndex,
|
||||
newStructuredList, newStructuredIndex);
|
||||
++StructuredIndex;
|
||||
++Index;
|
||||
return;
|
||||
}
|
||||
assert(SemaRef.getLangOpts().CPlusPlus &&
|
||||
"non-aggregate records are only possible in C++");
|
||||
// C++ initialization is handled later.
|
||||
}
|
||||
|
||||
if (ElemType->isScalarType()) {
|
||||
return CheckScalarType(Entity, IList, ElemType, Index,
|
||||
StructuredList, StructuredIndex);
|
||||
} else if (ElemType->isReferenceType()) {
|
||||
|
|
|
@ -0,0 +1,113 @@
|
|||
// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
|
||||
|
||||
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) {}
|
||||
};
|
||||
|
||||
struct string {
|
||||
string(const char *);
|
||||
};
|
||||
|
||||
template<typename A, typename B>
|
||||
struct pair {
|
||||
pair(const A&, const B&);
|
||||
};
|
||||
}
|
||||
|
||||
namespace bullet2 {
|
||||
double ad[] = { 1, 2.0 };
|
||||
int ai[] = { 1, 2.0 }; // expected-error {{type 'double' cannot be narrowed to 'int' in initializer list}} expected-note {{override}}
|
||||
|
||||
struct S2 {
|
||||
int m1;
|
||||
double m2, m3;
|
||||
};
|
||||
|
||||
S2 s21 = { 1, 2, 3.0 };
|
||||
S2 s22 { 1.0, 2, 3 }; // expected-error {{type 'double' cannot be narrowed to 'int' in initializer list}} expected-note {{override}}
|
||||
S2 s23 { };
|
||||
}
|
||||
|
||||
namespace bullet4_example1 {
|
||||
struct S {
|
||||
S(std::initializer_list<double> d) {}
|
||||
S(std::initializer_list<int> i) {}
|
||||
S() {}
|
||||
};
|
||||
|
||||
S s1 = { 1.0, 2.0, 3.0 };
|
||||
S s2 = { 1, 2, 3 };
|
||||
S s3 = { };
|
||||
}
|
||||
|
||||
namespace bullet4_example2 {
|
||||
struct Map {
|
||||
Map(std::initializer_list<std::pair<std::string,int>>) {}
|
||||
};
|
||||
|
||||
Map ship = {{"Sophie",14}, {"Surprise",28}};
|
||||
}
|
||||
|
||||
namespace bullet4_example3 {
|
||||
struct S {
|
||||
S(int, double, double) {}
|
||||
S() {}
|
||||
};
|
||||
|
||||
S s1 = { 1, 2, 3.0 };
|
||||
// FIXME: This is an ill-formed narrowing initialization.
|
||||
S s2 { 1.0, 2, 3 };
|
||||
S s3 {};
|
||||
}
|
||||
|
||||
namespace bullet5 {
|
||||
struct S {
|
||||
S(std::initializer_list<double>) {}
|
||||
S(const std::string &) {}
|
||||
};
|
||||
|
||||
const S& r1 = { 1, 2, 3.0 };
|
||||
const S& r2 = { "Spinach" };
|
||||
S& r3 = { 1, 2, 3 }; // expected-error {{non-const lvalue reference to type 'bullet5::S' cannot bind to an initializer list temporary}}
|
||||
const int& i1 = { 1 };
|
||||
const int& i2 = { 1.1 }; // expected-error {{type 'double' cannot be narrowed to 'int' in initializer list}} expected-note {{override}} expected-warning {{implicit conversion}}
|
||||
const int (&iar)[2] = { 1, 2 };
|
||||
}
|
||||
|
||||
namespace bullet6 {
|
||||
int x1 {2};
|
||||
int x2 {2.0}; // expected-error {{type 'double' cannot be narrowed to 'int' in initializer list}} expected-note {{override}}
|
||||
}
|
||||
|
||||
namespace bullet7 {
|
||||
int** pp {};
|
||||
}
|
||||
|
||||
namespace bullet8 {
|
||||
struct A { int i; int j; };
|
||||
A a1 { 1, 2 };
|
||||
A a2 { 1.2 }; // expected-error {{type 'double' cannot be narrowed to 'int' in initializer list}} expected-note {{override}} expected-warning {{implicit conversion}}
|
||||
|
||||
struct B {
|
||||
B(std::initializer_list<int> i) {}
|
||||
};
|
||||
B b1 { 1, 2 };
|
||||
B b2 { 1, 2.0 };
|
||||
|
||||
struct C {
|
||||
C(int i, double j) {}
|
||||
};
|
||||
C c1 = { 1, 2.2 };
|
||||
// FIXME: This is an ill-formed narrowing initialization.
|
||||
C c2 = { 1.1, 2 }; // expected-warning {{implicit conversion}}
|
||||
|
||||
int j { 1 };
|
||||
int k { };
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
// RUN: %clang_cc1 -std=c++11 -S -emit-llvm -o - %s | FileCheck %s
|
||||
|
||||
struct S {
|
||||
S(int x) { }
|
||||
S(int x, double y, double z) { }
|
||||
};
|
||||
|
||||
void fn1() {
|
||||
// CHECK: define void @_Z3fn1v
|
||||
S s { 1 };
|
||||
// CHECK: alloca %struct.S, align 1
|
||||
// CHECK: call void @_ZN1SC1Ei(%struct.S* %s, i32 1)
|
||||
}
|
||||
|
||||
void fn2() {
|
||||
// CHECK: define void @_Z3fn2v
|
||||
S s { 1, 2.0, 3.0 };
|
||||
// CHECK: alloca %struct.S, align 1
|
||||
// CHECK: call void @_ZN1SC1Eidd(%struct.S* %s, i32 1, double 2.000000e+00, double 3.000000e+00)
|
||||
}
|
||||
|
||||
void fn3() {
|
||||
// CHECK: define void @_Z3fn3v
|
||||
S sa[] { { 1 }, { 2 }, { 3 } };
|
||||
// CHECK: alloca [3 x %struct.S], align 1
|
||||
// CHECK: call void @_ZN1SC1Ei(%struct.S* %arrayinit.begin, i32 1)
|
||||
// CHECK: call void @_ZN1SC1Ei(%struct.S* %arrayinit.element, i32 2)
|
||||
// CHECK: call void @_ZN1SC1Ei(%struct.S* %arrayinit.element1, i32 3)
|
||||
}
|
||||
|
||||
void fn4() {
|
||||
// CHECK: define void @_Z3fn4v
|
||||
S sa[] { { 1, 2.0, 3.0 }, { 4, 5.0, 6.0 } };
|
||||
// CHECK: alloca [2 x %struct.S], align 1
|
||||
// CHECK: call void @_ZN1SC1Eidd(%struct.S* %arrayinit.begin, i32 1, double 2.000000e+00, double 3.000000e+00)
|
||||
// CHECK: call void @_ZN1SC1Eidd(%struct.S* %arrayinit.element, i32 4, double 5.000000e+00, double 6.000000e+00)
|
||||
}
|
|
@ -1318,3 +1318,15 @@ namespace PR13273 {
|
|||
// actually call it.
|
||||
static_assert(S{}.t == 0, "");
|
||||
}
|
||||
|
||||
namespace PR12670 {
|
||||
struct S {
|
||||
constexpr S(int a0) : m(a0) {}
|
||||
constexpr S() : m(6) {}
|
||||
int m;
|
||||
};
|
||||
constexpr S x[3] = { {4}, 5 };
|
||||
static_assert(x[0].m == 4, "");
|
||||
static_assert(x[1].m == 5, "");
|
||||
static_assert(x[2].m == 6, "");
|
||||
}
|
||||
|
|
|
@ -87,3 +87,32 @@ namespace array_explicit_conversion {
|
|||
(void)test4{{{1}}}; // expected-note {{in instantiation of template class 'array_explicit_conversion::A<-1>' requested here}}
|
||||
}
|
||||
}
|
||||
|
||||
namespace sub_constructor {
|
||||
struct DefaultConstructor { // expected-note 2 {{not viable}}
|
||||
DefaultConstructor(); // expected-note {{not viable}}
|
||||
int x;
|
||||
};
|
||||
struct NoDefaultConstructor1 { // expected-note 2 {{not viable}}
|
||||
NoDefaultConstructor1(int); // expected-note {{not viable}}
|
||||
int x;
|
||||
};
|
||||
struct NoDefaultConstructor2 { // expected-note 4 {{not viable}}
|
||||
NoDefaultConstructor2(int,int); // expected-note 2 {{not viable}}
|
||||
int x;
|
||||
};
|
||||
|
||||
struct Aggr {
|
||||
DefaultConstructor a;
|
||||
NoDefaultConstructor1 b;
|
||||
NoDefaultConstructor2 c;
|
||||
};
|
||||
|
||||
Aggr ok1 { {}, {0} , {0,0} };
|
||||
Aggr ok2 = { {}, {0} , {0,0} };
|
||||
Aggr too_many { {0} , {0} , {0,0} }; // expected-error {{no matching constructor for initialization}}
|
||||
Aggr too_few { {} , {0} , {0} }; // expected-error {{no matching constructor for initialization}}
|
||||
Aggr invalid { {} , {&ok1} , {0,0} }; // expected-error {{no matching constructor for initialization}}
|
||||
NoDefaultConstructor2 array_ok[] = { {0,0} , {0,1} };
|
||||
NoDefaultConstructor2 array_error[] = { {0,0} , {0} }; // expected-error {{no matching constructor for initialization}}
|
||||
}
|
|
@ -15,7 +15,7 @@ struct NonAggregate {
|
|||
};
|
||||
NonAggregate non_aggregate_test = { 1, 2 }; // expected-error{{non-aggregate type 'NonAggregate' cannot be initialized with an initializer list}}
|
||||
|
||||
NonAggregate non_aggregate_test2[2] = { { 1, 2 }, { 3, 4 } }; // expected-error 2 {{initialization of non-aggregate type 'NonAggregate' with an initializer list}}
|
||||
NonAggregate non_aggregate_test2[2] = { { 1, 2 }, { 3, 4 } }; // expected-error 2 {{non-aggregate type 'NonAggregate' cannot be initialized with an initializer list}}
|
||||
|
||||
|
||||
// C++ [dcl.init.aggr]p3
|
||||
|
|
Loading…
Reference in New Issue