From: Eli Friedman Date: Sat, 19 Dec 2009 08:11:05 +0000 (+0000) Subject: Initialization improvements: addition of string initialization and a few X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=cfdc81a83467973b14e4ea5e9e9af1690f135415;p=clang Initialization improvements: addition of string initialization and a few small bug fixes in SemaInit, switch over SemaDecl to use it more often, and change a bunch of diagnostics which are different with the new initialization code. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@91767 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 587c141b4b..4b960e81a5 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -3525,26 +3525,22 @@ void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit) { Diag(VDecl->getLocation(), diag::err_block_extern_cant_init); VDecl->setInvalidDecl(); } else if (!VDecl->isInvalidDecl()) { - if (VDecl->getType()->isReferenceType() - || isa(Init)) { - InitializationSequence InitSeq(*this, Entity, Kind, &Init, 1); - if (InitSeq) { - OwningExprResult Result = InitSeq.Perform(*this, Entity, Kind, - MultiExprArg(*this, (void**)&Init, 1), - &DclT); - if (Result.isInvalid()) { - VDecl->setInvalidDecl(); - return; - } - - Init = Result.takeAs(); - } else { - InitSeq.Diagnose(*this, Entity, Kind, &Init, 1); + InitializationSequence InitSeq(*this, Entity, Kind, &Init, 1); + if (InitSeq) { + OwningExprResult Result = InitSeq.Perform(*this, Entity, Kind, + MultiExprArg(*this, (void**)&Init, 1), + &DclT); + if (Result.isInvalid()) { VDecl->setInvalidDecl(); return; - } - } else if (CheckInitializerTypes(Init, DclT, Entity, Kind)) + } + + Init = Result.takeAs(); + } else { + InitSeq.Diagnose(*this, Entity, Kind, &Init, 1); VDecl->setInvalidDecl(); + return; + } // C++ 3.6.2p2, allow dynamic initialization of static initializers. // Don't check invalid declarations to avoid emitting useless diagnostics. diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index 6f11a87d11..44f6cf3d74 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -1988,6 +1988,7 @@ void InitializationSequence::Step::Destroy() { case SK_ConstructorInitialization: case SK_ZeroInitialization: case SK_CAssignment: + case SK_StringInit: break; case SK_ConversionSequence: @@ -2080,6 +2081,13 @@ void InitializationSequence::AddCAssignmentStep(QualType T) { Steps.push_back(S); } +void InitializationSequence::AddStringInitStep(QualType T) { + Step S; + S.Kind = SK_StringInit; + S.Type = T; + Steps.push_back(S); +} + void InitializationSequence::SetOverloadFailure(FailureKind Failure, OverloadingResult Result) { SequenceKind = FailedSequence; @@ -2492,7 +2500,8 @@ static void TryStringLiteralInitialization(Sema &S, const InitializationKind &Kind, Expr *Initializer, InitializationSequence &Sequence) { - // FIXME: Implement! + Sequence.setSequenceKind(InitializationSequence::StringInit); + Sequence.AddStringInitStep(Entity.getType().getType()); } /// \brief Attempt initialization by constructor (C++ [dcl.init]), which @@ -2711,10 +2720,17 @@ static void TryUserDefinedConversion(Sema &S, } } } - + + SourceLocation DeclLoc = Initializer->getLocStart(); + if (const RecordType *SourceRecordType = SourceType->getAs()) { // The type we're converting from is a class type, enumerate its conversion // functions. + + // Try to force the type to be complete before enumerating the conversion + // functions; it's okay if this fails, though. + S.RequireCompleteType(DeclLoc, SourceType, 0); + CXXRecordDecl *SourceRecordDecl = cast(SourceRecordType->getDecl()); @@ -2746,8 +2762,6 @@ static void TryUserDefinedConversion(Sema &S, } } - SourceLocation DeclLoc = Initializer->getLocStart(); - // Perform overload resolution. If it fails, return the failed result. OverloadCandidateSet::iterator Best; if (OverloadingResult Result @@ -2876,13 +2890,6 @@ InitializationSequence::InitializationSequence(Sema &S, return; } - // Handle initialization in C - if (!S.getLangOptions().CPlusPlus) { - setSequenceKind(CAssignment); - AddCAssignmentStep(DestType); - return; - } - // - Otherwise, if the destination type is an array, the program is // ill-formed. if (const ArrayType *AT = Context.getAsArrayType(DestType)) { @@ -2893,6 +2900,13 @@ InitializationSequence::InitializationSequence(Sema &S, return; } + + // Handle initialization in C + if (!S.getLangOptions().CPlusPlus) { + setSequenceKind(CAssignment); + AddCAssignmentStep(DestType); + return; + } // - If the destination type is a (possibly cv-qualified) class type: if (DestType->isRecordType()) { @@ -3187,6 +3201,7 @@ InitializationSequence::Perform(Sema &S, case SK_ConversionSequence: case SK_ListInitialization: case SK_CAssignment: + case SK_StringInit: assert(Args.size() == 1); CurInit = Sema::OwningExprResult(S, ((Expr **)(Args.get()))[0]->Retain()); if (CurInit.isInvalid()) @@ -3425,6 +3440,12 @@ InitializationSequence::Perform(Sema &S, CurInit = S.Owned(CurInitExpr); break; } + + case SK_StringInit: { + QualType Ty = Step->Type; + CheckStringInit(CurInitExpr, ResultType ? *ResultType : Ty, S); + break; + } } } diff --git a/lib/Sema/SemaInit.h b/lib/Sema/SemaInit.h index 1987ad0734..85f3d2c1a3 100644 --- a/lib/Sema/SemaInit.h +++ b/lib/Sema/SemaInit.h @@ -389,7 +389,10 @@ public: StandardConversion, /// \brief C conversion sequence. - CAssignment + CAssignment, + + /// \brief String initialization + StringInit }; /// \brief Describes the kind of a particular step in an initialization @@ -422,7 +425,9 @@ public: /// \brief Zero-initialize the object SK_ZeroInitialization, /// \brief C assignment - SK_CAssignment + SK_CAssignment, + /// \brief Initialization by string + SK_StringInit }; /// \brief A single step in the initialization sequence. @@ -632,6 +637,9 @@ public: // path. However, that isn't the case yet. void AddCAssignmentStep(QualType T); + /// \brief Add a string init step. + void AddStringInitStep(QualType T); + /// \brief Note that this initialization sequence failed. void SetFailed(FailureKind Failure) { SequenceKind = FailedSequence; diff --git a/test/CXX/class/class.local/p2.cpp b/test/CXX/class/class.local/p2.cpp index a1fed53b3c..56ff1e53a4 100644 --- a/test/CXX/class/class.local/p2.cpp +++ b/test/CXX/class/class.local/p2.cpp @@ -7,6 +7,5 @@ void f() { B b; - A *a = &b; // expected-error{{conversion from 'struct B' to inaccessible base class 'struct A'}} \ - expected-error{{incompatible type initializing 'struct B *', expected 'struct A *'}} + A *a = &b; // expected-error{{conversion from 'struct B' to inaccessible base class 'struct A'}} } diff --git a/test/CXX/dcl.decl/dcl.meaning/dcl.mptr/p3.cpp b/test/CXX/dcl.decl/dcl.meaning/dcl.mptr/p3.cpp index 1635ca792f..561e26b068 100644 --- a/test/CXX/dcl.decl/dcl.meaning/dcl.mptr/p3.cpp +++ b/test/CXX/dcl.decl/dcl.meaning/dcl.mptr/p3.cpp @@ -16,7 +16,7 @@ void f() { int b; A a(b); - int A::*ip = &A::s; // expected-error {{incompatible type initializing 'int *', expected 'int class A::*'}} + int A::*ip = &A::s; // expected-error {{cannot initialize a variable of type 'int class A::*' with an rvalue of type 'int *'}} a.*&A::s = 10; // expected-error{{right hand operand to .* has non pointer-to-member type 'int *'}} a.*&A::i = 10; // expected-error{{cannot form a pointer-to-member to member 'i' of reference type 'int &'}} diff --git a/test/CXX/over/over.over/p2.cpp b/test/CXX/over/over.over/p2.cpp index 70c786b395..e8840d205e 100644 --- a/test/CXX/over/over.over/p2.cpp +++ b/test/CXX/over/over.over/p2.cpp @@ -5,6 +5,6 @@ template T f0(T, T); void test_f0() { int (*f0a)(int, int) = f0; int (*f0b)(int, int) = &f0; - int (*f0c)(int, float) = f0; // expected-error{{incompatible type}} + int (*f0c)(int, float) = f0; // expected-error{{cannot initialize}} // FIXME: poor error message above! } diff --git a/test/CXX/over/over.over/p4.cpp b/test/CXX/over/over.over/p4.cpp index b1837b81c3..4189218f65 100644 --- a/test/CXX/over/over.over/p4.cpp +++ b/test/CXX/over/over.over/p4.cpp @@ -18,6 +18,6 @@ int f0(int); void test_f0_2() { using namespace N; int (*fp0)(int) = f0; // expected-error{{ambiguous}} \ - // expected-error{{initializing}} + // expected-error{{cannot initialize}} float (*fp1)(float) = f0; } diff --git a/test/Sema/array-init.c b/test/Sema/array-init.c index fbcf06bd16..45d3183852 100644 --- a/test/Sema/array-init.c +++ b/test/Sema/array-init.c @@ -167,7 +167,7 @@ void charArrays() { void variableArrayInit() { int a = 4; - char strlit[a] = "foo"; //expected-error{{variable-sized object may not be initialized}} + char strlit[a] = "foo"; //expected-error{{array initializer must be an initializer list or string literal}} int b[a] = { 1, 2, 4 }; //expected-error{{variable-sized object may not be initialized}} } diff --git a/test/Sema/init.c b/test/Sema/init.c index 9ebbce9758..c2712480c6 100644 --- a/test/Sema/init.c +++ b/test/Sema/init.c @@ -20,7 +20,7 @@ int *h = &x; int test() { int a[10]; -int b[10] = a; // expected-error {{initialization with '{...}' expected}} +int b[10] = a; // expected-error {{array initializer must be an initializer list}} int +; // expected-error {{expected identifier or '('}} } diff --git a/test/Sema/wchar.c b/test/Sema/wchar.c index edec2b30ce..28ec2f14ce 100644 --- a/test/Sema/wchar.c +++ b/test/Sema/wchar.c @@ -17,6 +17,6 @@ int check_wchar_size[sizeof(*L"") == sizeof(wchar_t) ? 1 : -1]; void foo() { WCHAR_T_TYPE t1[] = L"x"; wchar_t tab[] = L"x"; - WCHAR_T_TYPE t2[] = "x"; // expected-error {{initialization}} - char t3[] = L"x"; // expected-error {{initialization}} + WCHAR_T_TYPE t2[] = "x"; // expected-error {{initializer}} + char t3[] = L"x"; // expected-error {{initializer}} } diff --git a/test/SemaCXX/access-base-class.cpp b/test/SemaCXX/access-base-class.cpp index 6956553f83..f4c58d940b 100644 --- a/test/SemaCXX/access-base-class.cpp +++ b/test/SemaCXX/access-base-class.cpp @@ -5,8 +5,7 @@ class A { }; class B : private A { }; // expected-note {{'private' inheritance specifier here}} void f(B* b) { - A *a = b; // expected-error{{conversion from 'class T1::B' to inaccessible base class 'class T1::A'}} \ - expected-error{{incompatible type initializing 'class T1::B *', expected 'class T1::A *'}} + A *a = b; // expected-error{{conversion from 'class T1::B' to inaccessible base class 'class T1::A'}} } } @@ -17,8 +16,7 @@ class A { }; class B : A { }; // expected-note {{inheritance is implicitly 'private'}} void f(B* b) { - A *a = b; // expected-error {{conversion from 'class T2::B' to inaccessible base class 'class T2::A'}} \ - expected-error {{incompatible type initializing 'class T2::B *', expected 'class T2::A *'}} + A *a = b; // expected-error {{conversion from 'class T2::B' to inaccessible base class 'class T2::A'}} } } @@ -71,8 +69,7 @@ namespace T6 { class C : public B { void f(C *c) { - A* a = c; // expected-error {{conversion from 'class T6::C' to inaccessible base class 'class T6::A'}} \ - expected-error {{incompatible type initializing 'class T6::C *', expected 'class T6::A *'}} + A* a = c; // expected-error {{conversion from 'class T6::C' to inaccessible base class 'class T6::A'}} } }; diff --git a/test/SemaCXX/bool.cpp b/test/SemaCXX/bool.cpp index c0367aa3e5..44e17ce62b 100644 --- a/test/SemaCXX/bool.cpp +++ b/test/SemaCXX/bool.cpp @@ -14,7 +14,7 @@ void test(bool b) --b; // expected-error {{cannot decrement expression of type bool}} b--; // expected-error {{cannot decrement expression of type bool}} - bool *b1 = (int *)0; // expected-error{{expected 'bool *'}} + bool *b1 = (int *)0; // expected-error{{cannot initialize}} } // static_assert_arg_is_bool(x) compiles only if x is a bool. diff --git a/test/SemaCXX/condition.cpp b/test/SemaCXX/condition.cpp index aede25e3f7..a0b57e1baa 100644 --- a/test/SemaCXX/condition.cpp +++ b/test/SemaCXX/condition.cpp @@ -6,7 +6,7 @@ void test() { if (int x=0) ++x; typedef int arr[10]; - while (arr x=0) ; // expected-error {{an array type is not allowed here}} expected-error {{initialization with '{...}' expected for array}} + while (arr x=0) ; // expected-error {{an array type is not allowed here}} expected-error {{array initializer must be an initializer list}} while (int f()=0) ; // expected-error {{a function type is not allowed here}} struct S {} s; @@ -18,7 +18,7 @@ void test() { while (struct S {} x=0) ; // expected-error {{types may not be defined in conditions}} expected-error {{no viable conversion}} expected-error {{value of type 'struct S' is not contextually convertible to 'bool'}} expected-note{{candidate function}} while (struct {} x=0) ; // expected-error {{types may not be defined in conditions}} expected-error {{no viable conversion}} expected-error {{value of type 'struct ' is not contextually convertible to 'bool'}} expected-note{{candidate function}} - switch (enum {E} x=0) ; // expected-error {{types may not be defined in conditions}} expected-error {{incompatible type}} + switch (enum {E} x=0) ; // expected-error {{types may not be defined in conditions}} expected-error {{cannot initialize}} if (int x=0) { // expected-note 2 {{previous definition is here}} int x; // expected-error {{redefinition of 'x'}} diff --git a/test/SemaCXX/convert-to-bool.cpp b/test/SemaCXX/convert-to-bool.cpp index 543f6b1f01..4b5002e44a 100644 --- a/test/SemaCXX/convert-to-bool.cpp +++ b/test/SemaCXX/convert-to-bool.cpp @@ -44,7 +44,7 @@ struct ExplicitConvToRef { void test_explicit_bool(ExplicitConvToBool ecb) { bool b1(ecb); // okay - bool b2 = ecb; // expected-error{{incompatible type initializing 'struct ExplicitConvToBool', expected 'bool'}} + bool b2 = ecb; // expected-error{{no viable conversion from 'struct ExplicitConvToBool' to 'bool'}} accepts_bool(ecb); // expected-error{{no matching function for call to}} } diff --git a/test/SemaCXX/deleted-function.cpp b/test/SemaCXX/deleted-function.cpp index c827b6e75e..572ef34330 100644 --- a/test/SemaCXX/deleted-function.cpp +++ b/test/SemaCXX/deleted-function.cpp @@ -18,7 +18,7 @@ void ov(double) = delete; // expected-note {{candidate function has been explici struct WithDel { WithDel() = delete; // expected-note {{candidate function has been explicitly deleted}} void fn() = delete; // expected-note {{function has been explicitly marked deleted here}} - operator int() = delete; + operator int() = delete; // expected-note {{function has been explicitly marked deleted here}} void operator +(int) = delete; int i = delete; // expected-error {{only functions can have deleted definitions}} @@ -32,5 +32,5 @@ void test() { WithDel dd; // expected-error {{call to deleted constructor of 'dd'}} WithDel *d = 0; d->fn(); // expected-error {{attempt to use a deleted function}} - int i = *d; // expected-error {{incompatible type initializing}} + int i = *d; // expected-error {{invokes a deleted function}} } diff --git a/test/SemaCXX/direct-initializer.cpp b/test/SemaCXX/direct-initializer.cpp index 4809daba95..0930ff798f 100644 --- a/test/SemaCXX/direct-initializer.cpp +++ b/test/SemaCXX/direct-initializer.cpp @@ -40,11 +40,11 @@ struct Base { }; struct Derived : Base { - operator int*(); + operator int*(); // expected-note {{candidate function}} }; void foo(const Derived cd, Derived d) { - int *pi = cd; // expected-error {{incompatible type initializing 'struct Derived const', expected 'int *'}} + int *pi = cd; // expected-error {{no viable conversion from 'struct Derived const' to 'int *'}} int *ppi = d; } diff --git a/test/SemaCXX/exception-spec.cpp b/test/SemaCXX/exception-spec.cpp index c46da15bec..291b359dfd 100644 --- a/test/SemaCXX/exception-spec.cpp +++ b/test/SemaCXX/exception-spec.cpp @@ -160,11 +160,11 @@ void fnptrs() // return types and arguments must match exactly, no inheritance allowed void (*(*t7)())() throw(B1) = &s8; // valid - void (*(*t8)())() throw(A) = &s8; // expected-error {{return types differ}} expected-error {{incompatible type}} - void (*(*t9)())() throw(D) = &s8; // expected-error {{return types differ}} expected-error {{incompatible type}} + void (*(*t8)())() throw(A) = &s8; // expected-error {{return types differ}} + void (*(*t9)())() throw(D) = &s8; // expected-error {{return types differ}} void (*t10)(void (*)() throw(B1)) = &s9; // valid expected-warning{{disambiguated}} - void (*t11)(void (*)() throw(A)) = &s9; // expected-error {{argument types differ}} expected-error {{incompatible type}} expected-warning{{disambiguated}} - void (*t12)(void (*)() throw(D)) = &s9; // expected-error {{argument types differ}} expected-error {{incompatible type}} expected-warning{{disambiguated}} + void (*t11)(void (*)() throw(A)) = &s9; // expected-error {{argument types differ}} expected-warning{{disambiguated}} + void (*t12)(void (*)() throw(D)) = &s9; // expected-error {{argument types differ}} expected-warning{{disambiguated}} } // Member function stuff @@ -178,7 +178,7 @@ void mfnptr() { void (Str1::*pfn1)() throw(int) = &Str1::f; // valid void (Str1::*pfn2)() = &Str1::f; // valid - void (Str1::*pfn3)() throw() = &Str1::f; // expected-error {{not superset}} expected-error {{incompatible type}} + void (Str1::*pfn3)() throw() = &Str1::f; // expected-error {{not superset}} } // Don't suppress errors in template instantiation. diff --git a/test/SemaCXX/member-pointer.cpp b/test/SemaCXX/member-pointer.cpp index f51ebc51a1..65d05eb5af 100644 --- a/test/SemaCXX/member-pointer.cpp +++ b/test/SemaCXX/member-pointer.cpp @@ -35,8 +35,8 @@ void f() { pdid = pdi2; // Fail conversion due to ambiguity and virtuality. - int F::*pdif = pdi1; // expected-error {{ambiguous conversion from pointer to member of base class 'struct A' to pointer to member of derived class 'struct F'}} expected-error {{incompatible type}} - int G::*pdig = pdi1; // expected-error {{conversion from pointer to member of class 'struct A' to pointer to member of class 'struct G' via virtual base 'struct D' is not allowed}} expected-error {{incompatible type}} + int F::*pdif = pdi1; // expected-error {{ambiguous conversion from pointer to member of base class 'struct A' to pointer to member of derived class 'struct F'}} + int G::*pdig = pdi1; // expected-error {{conversion from pointer to member of class 'struct A' to pointer to member of class 'struct G' via virtual base 'struct D' is not allowed}} // Conversion to member of base. pdi1 = pdid; // expected-error {{incompatible type assigning 'int struct D::*', expected 'int struct A::*'}} diff --git a/test/SemaCXX/nullptr.cpp b/test/SemaCXX/nullptr.cpp index 445f33cdcc..a3aab7fbe3 100644 --- a/test/SemaCXX/nullptr.cpp +++ b/test/SemaCXX/nullptr.cpp @@ -29,7 +29,7 @@ nullptr_t f(nullptr_t null) bool b = nullptr; // Can't convert nullptr to integral implicitly. - uintptr_t i = nullptr; // expected-error {{incompatible type initializing}} + uintptr_t i = nullptr; // expected-error {{cannot initialize}} // Operators (void)(null == nullptr); diff --git a/test/SemaObjCXX/conditional-expr.mm b/test/SemaObjCXX/conditional-expr.mm index 0857ae27d5..a6b7c08e8f 100644 --- a/test/SemaObjCXX/conditional-expr.mm +++ b/test/SemaObjCXX/conditional-expr.mm @@ -27,11 +27,11 @@ void f1(id x, A *a) { } void f2(id x) { - id l = x; // expected-error {{incompatible type initializing 'id', expected 'id'}} + id l = x; // expected-error {{cannot initialize a variable of type 'id' with an lvalue of type 'id'}} } void f3(A *a) { - id l = a; // expected-error {{incompatible type initializing 'A *', expected 'id'}} + id l = a; // expected-error {{cannot initialize a variable of type 'id' with an lvalue of type 'A *'}} } void f4(int cond, id x, A *a) { diff --git a/test/SemaTemplate/fun-template-def.cpp b/test/SemaTemplate/fun-template-def.cpp index cc28553ebc..0c2cf9c4f2 100644 --- a/test/SemaTemplate/fun-template-def.cpp +++ b/test/SemaTemplate/fun-template-def.cpp @@ -8,7 +8,7 @@ // Fake typeid, lacking a typeinfo header. namespace std { class type_info {}; } -struct dummy {}; // expected-note{{candidate function}} +struct dummy {}; // expected-note 3 {{candidate function}} template int f0(T x) { @@ -39,9 +39,9 @@ T f1(T t1, U u1, int i1) new (t1, u1) int; delete t1; - dummy d1 = sizeof(t1); // FIXME: delayed checking okay? + dummy d1 = sizeof(t1); // expected-error {{no viable conversion}} dummy d2 = offsetof(T, foo); // expected-error {{no viable conversion}} - dummy d3 = __alignof(u1); // FIXME: delayed checking okay? + dummy d3 = __alignof(u1); // expected-error {{no viable conversion}} i1 = typeid(t1); // expected-error {{incompatible type assigning}} return u1; diff --git a/test/SemaTemplate/instantiate-method.cpp b/test/SemaTemplate/instantiate-method.cpp index 422364c155..a02fe5238c 100644 --- a/test/SemaTemplate/instantiate-method.cpp +++ b/test/SemaTemplate/instantiate-method.cpp @@ -79,7 +79,7 @@ template struct A1; int *a(A0 &x0, A1 &x1) { int *y0 = x0; - int *y1 = x1; // expected-error{{initializing}} + int *y1 = x1; // expected-error{{no viable conversion}} } struct X0Base {