diff options
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 290 | ||||
-rw-r--r-- | lib/Sema/SemaInit.cpp | 4 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiateDecl.cpp | 7 | ||||
-rw-r--r-- | test/CXX/dcl.decl/dcl.init/p6.cpp | 2 | ||||
-rw-r--r-- | test/CXX/expr/p8.cpp | 2 | ||||
-rw-r--r-- | test/CXX/temp/temp.decls/temp.mem/p5.cpp | 2 | ||||
-rw-r--r-- | test/Sema/incomplete-decl.c | 2 | ||||
-rw-r--r-- | test/SemaCXX/cast-conversion.cpp | 2 | ||||
-rw-r--r-- | test/SemaCXX/dcl_ambig_res.cpp | 4 | ||||
-rw-r--r-- | test/SemaTemplate/instantiate-declref-ice.cpp | 2 | ||||
-rw-r--r-- | test/SemaTemplate/instantiate-expr-4.cpp | 4 |
11 files changed, 133 insertions, 188 deletions
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 521b420e56..e12902bff6 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -3658,24 +3658,6 @@ void Sema::ActOnUninitializedDecl(DeclPtrTy dcl, if (VarDecl *Var = dyn_cast<VarDecl>(RealDecl)) { QualType Type = Var->getType(); - // Record tentative definitions. - if (Var->isTentativeDefinitionNow()) - TentativeDefinitions.push_back(Var); - - // C++ [dcl.init.ref]p3: - // The initializer can be omitted for a reference only in a - // parameter declaration (8.3.5), in the declaration of a - // function return type, in the declaration of a class member - // within its class declaration (9.2), and where the extern - // specifier is explicitly used. - if (Type->isReferenceType() && !Var->hasExternalStorage()) { - Diag(Var->getLocation(), diag::err_reference_var_requires_init) - << Var->getDeclName() - << SourceRange(Var->getLocation(), Var->getLocation()); - Var->setInvalidDecl(); - return; - } - // C++0x [dcl.spec.auto]p3 if (TypeContainsUndeducedAuto) { Diag(Var->getLocation(), diag::err_auto_var_requires_init) @@ -3684,99 +3666,133 @@ void Sema::ActOnUninitializedDecl(DeclPtrTy dcl, return; } - // An array without size is an incomplete type, and there are no special - // rules in C++ to make such a definition acceptable. - if (getLangOptions().CPlusPlus && Type->isIncompleteArrayType() && - !Var->hasExternalStorage()) { + switch (Var->isThisDeclarationADefinition()) { + case VarDecl::Definition: + if (!Var->isStaticDataMember() || !Var->getAnyInitializer()) + break; + + // We have an out-of-line definition of a static data member + // that has an in-class initializer, so we type-check this like + // a declaration. + // + // Fall through + + case VarDecl::DeclarationOnly: + // It's only a declaration. + + // Block scope. C99 6.7p7: If an identifier for an object is + // declared with no linkage (C99 6.2.2p6), the type for the + // object shall be complete. + if (!Type->isDependentType() && Var->isBlockVarDecl() && + !Var->getLinkage() && !Var->isInvalidDecl() && + RequireCompleteType(Var->getLocation(), Type, + diag::err_typecheck_decl_incomplete_type)) + Var->setInvalidDecl(); + + // Make sure that the type is not abstract. + if (!Type->isDependentType() && !Var->isInvalidDecl() && + RequireNonAbstractType(Var->getLocation(), Type, + diag::err_abstract_type_in_decl, + AbstractVariableType)) + Var->setInvalidDecl(); + return; + + case VarDecl::TentativeDefinition: + // File scope. C99 6.9.2p2: A declaration of an identifier for an + // object that has file scope without an initializer, and without a + // storage-class specifier or with the storage-class specifier "static", + // constitutes a tentative definition. Note: A tentative definition with + // external linkage is valid (C99 6.2.2p5). + if (!Var->isInvalidDecl()) { + if (const IncompleteArrayType *ArrayT + = Context.getAsIncompleteArrayType(Type)) { + if (RequireCompleteType(Var->getLocation(), + ArrayT->getElementType(), + diag::err_illegal_decl_array_incomplete_type)) + Var->setInvalidDecl(); + } else if (Var->getStorageClass() == VarDecl::Static) { + // C99 6.9.2p3: If the declaration of an identifier for an object is + // a tentative definition and has internal linkage (C99 6.2.2p3), the + // declared type shall not be an incomplete type. + // NOTE: code such as the following + // static struct s; + // struct s { int a; }; + // is accepted by gcc. Hence here we issue a warning instead of + // an error and we do not invalidate the static declaration. + // NOTE: to avoid multiple warnings, only check the first declaration. + if (Var->getPreviousDeclaration() == 0) + RequireCompleteType(Var->getLocation(), Type, + diag::ext_typecheck_decl_incomplete_type); + } + } + + // Record the tentative definition; we're done. + if (!Var->isInvalidDecl()) + TentativeDefinitions.push_back(Var); + return; + } + + // Provide a specific diagnostic for uninitialized variable + // definitions with incomplete array type. + if (Type->isIncompleteArrayType()) { Diag(Var->getLocation(), diag::err_typecheck_incomplete_array_needs_initializer); Var->setInvalidDecl(); return; } - // C++ [temp.expl.spec]p15: - // An explicit specialization of a static data member of a template is a - // definition if the declaration includes an initializer; otherwise, it - // is a declaration. - if (Var->isStaticDataMember() && - Var->getInstantiatedFromStaticDataMember() && - Var->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) + // Provide a specific diagnostic for uninitialized variable + // definitions with reference type. + if (Type->isReferenceType()) { + Diag(Var->getLocation(), diag::err_reference_var_requires_init) + << Var->getDeclName() + << SourceRange(Var->getLocation(), Var->getLocation()); + Var->setInvalidDecl(); + return; + } + + // Do not attempt to type-check the default initializer for a + // variable with dependent type. + if (Type->isDependentType()) return; - - // C++ [dcl.init]p9: - // If no initializer is specified for an object, and the object - // is of (possibly cv-qualified) non-POD class type (or array - // thereof), the object shall be default-initialized; if the - // object is of const-qualified type, the underlying class type - // shall have a user-declared default constructor. - // - // FIXME: Diagnose the "user-declared default constructor" bit. - if (getLangOptions().CPlusPlus) { - QualType InitType = Type; - if (const ArrayType *Array = Context.getAsArrayType(Type)) - InitType = Context.getBaseElementType(Array); - if ((!Var->hasExternalStorage() && !Var->isExternC()) && - InitType->isRecordType() && !InitType->isDependentType()) { - if (!RequireCompleteType(Var->getLocation(), InitType, - diag::err_invalid_incomplete_type_use)) { - InitializedEntity Entity - = InitializedEntity::InitializeVariable(Var); - InitializationKind Kind - = InitializationKind::CreateDefault(Var->getLocation()); - - InitializationSequence InitSeq(*this, Entity, Kind, 0, 0); - OwningExprResult Init = InitSeq.Perform(*this, Entity, Kind, - MultiExprArg(*this, 0, 0)); - if (Init.isInvalid()) - Var->setInvalidDecl(); - else { - if (Init.get()) - Var->setInit(Context, - MaybeCreateCXXExprWithTemporaries(Init.takeAs<Expr>())); - FinalizeVarWithDestructor(Var, InitType->getAs<RecordType>()); - } - } else { - Var->setInvalidDecl(); - } - } - // The variable can not have an abstract class type. - if (RequireNonAbstractType(Var->getLocation(), Type, - diag::err_abstract_type_in_decl, - AbstractVariableType)) - Var->setInvalidDecl(); + if (Var->isInvalidDecl()) + return; + + if (RequireCompleteType(Var->getLocation(), + Context.getBaseElementType(Type), + diag::err_typecheck_decl_incomplete_type)) { + Var->setInvalidDecl(); + return; } -#if 0 - // FIXME: Temporarily disabled because we are not properly parsing - // linkage specifications on declarations, e.g., - // - // extern "C" const CGPoint CGPointerZero; - // - // C++ [dcl.init]p9: - // - // If no initializer is specified for an object, and the - // object is of (possibly cv-qualified) non-POD class type (or - // array thereof), the object shall be default-initialized; if - // the object is of const-qualified type, the underlying class - // type shall have a user-declared default - // constructor. Otherwise, if no initializer is specified for - // an object, the object and its subobjects, if any, have an - // indeterminate initial value; if the object or any of its - // subobjects are of const-qualified type, the program is - // ill-formed. - // - // This isn't technically an error in C, so we don't diagnose it. - // - // FIXME: Actually perform the POD/user-defined default - // constructor check. - if (getLangOptions().CPlusPlus && - Context.getCanonicalType(Type).isConstQualified() && - !Var->hasExternalStorage()) - Diag(Var->getLocation(), diag::err_const_var_requires_init) - << Var->getName() - << SourceRange(Var->getLocation(), Var->getLocation()); -#endif + // The variable can not have an abstract class type. + if (RequireNonAbstractType(Var->getLocation(), Type, + diag::err_abstract_type_in_decl, + AbstractVariableType)) { + Var->setInvalidDecl(); + return; + } + + InitializedEntity Entity = InitializedEntity::InitializeVariable(Var); + InitializationKind Kind + = InitializationKind::CreateDefault(Var->getLocation()); + + InitializationSequence InitSeq(*this, Entity, Kind, 0, 0); + OwningExprResult Init = InitSeq.Perform(*this, Entity, Kind, + MultiExprArg(*this, 0, 0)); + if (Init.isInvalid()) + Var->setInvalidDecl(); + else { + if (Init.get()) + Var->setInit(Context, + MaybeCreateCXXExprWithTemporaries(Init.takeAs<Expr>())); + + if (getLangOptions().CPlusPlus) + if (const RecordType *Record + = Context.getBaseElementType(Type)->getAs<RecordType>()) + FinalizeVarWithDestructor(Var, Record); + } } } @@ -3792,78 +3808,6 @@ Sema::DeclGroupPtrTy Sema::FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS, if (Decl *D = Group[i].getAs<Decl>()) Decls.push_back(D); - // Perform semantic analysis that depends on having fully processed both - // the declarator and initializer. - for (unsigned i = 0, e = Decls.size(); i != e; ++i) { - VarDecl *IDecl = dyn_cast<VarDecl>(Decls[i]); - if (!IDecl) - continue; - QualType T = IDecl->getType(); - - // Block scope. C99 6.7p7: If an identifier for an object is declared with - // no linkage (C99 6.2.2p6), the type for the object shall be complete... - if (IDecl->isBlockVarDecl() && !IDecl->hasExternalStorage()) { - if (T->isDependentType()) { - // If T is dependent, we should not require a complete type. - // (RequireCompleteType shouldn't be called with dependent types.) - // But we still can at least check if we've got an array of unspecified - // size without an initializer. - if (!IDecl->isInvalidDecl() && T->isIncompleteArrayType() && - !IDecl->getInit()) { - Diag(IDecl->getLocation(), diag::err_typecheck_decl_incomplete_type) - << T; - IDecl->setInvalidDecl(); - } - } else if (!IDecl->isInvalidDecl()) { - // If T is an incomplete array type with an initializer list that is - // dependent on something, its size has not been fixed. We could attempt - // to fix the size for such arrays, but we would still have to check - // here for initializers containing a C++0x vararg expansion, e.g. - // template <typename... Args> void f(Args... args) { - // int vals[] = { args }; - // } - const IncompleteArrayType *IAT = Context.getAsIncompleteArrayType(T); - Expr *Init = IDecl->getInit(); - if (IAT && Init && - (Init->isTypeDependent() || Init->isValueDependent())) { - // Check that the member type of the array is complete, at least. - if (RequireCompleteType(IDecl->getLocation(), IAT->getElementType(), - diag::err_typecheck_decl_incomplete_type)) - IDecl->setInvalidDecl(); - } else if (RequireCompleteType(IDecl->getLocation(), T, - diag::err_typecheck_decl_incomplete_type)) - IDecl->setInvalidDecl(); - } - } - // File scope. C99 6.9.2p2: A declaration of an identifier for an - // object that has file scope without an initializer, and without a - // storage-class specifier or with the storage-class specifier "static", - // constitutes a tentative definition. Note: A tentative definition with - // external linkage is valid (C99 6.2.2p5). - if (IDecl->isThisDeclarationADefinition() == VarDecl::TentativeDefinition && - !IDecl->isInvalidDecl()) { - if (const IncompleteArrayType *ArrayT - = Context.getAsIncompleteArrayType(T)) { - if (RequireCompleteType(IDecl->getLocation(), - ArrayT->getElementType(), - diag::err_illegal_decl_array_incomplete_type)) - IDecl->setInvalidDecl(); - } else if (IDecl->getStorageClass() == VarDecl::Static) { - // C99 6.9.2p3: If the declaration of an identifier for an object is - // a tentative definition and has internal linkage (C99 6.2.2p3), the - // declared type shall not be an incomplete type. - // NOTE: code such as the following - // static struct s; - // struct s { int a; }; - // is accepted by gcc. Hence here we issue a warning instead of - // an error and we do not invalidate the static declaration. - // NOTE: to avoid multiple warnings, only check the first declaration. - if (IDecl->getPreviousDeclaration() == 0) - RequireCompleteType(IDecl->getLocation(), T, - diag::ext_typecheck_decl_incomplete_type); - } - } - } return DeclGroupPtrTy::make(DeclGroupRef::Create(Context, Decls.data(), Decls.size())); } diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index 3e710cfd5a..d47b8caec0 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -2650,7 +2650,7 @@ static void TryDefaultInitialization(Sema &S, // - if T is a (possibly cv-qualified) class type (Clause 9), the default // constructor for T is called (and the initialization is ill-formed if // T has no accessible default constructor); - if (DestType->isRecordType()) { + if (DestType->isRecordType() && S.getLangOptions().CPlusPlus) { return TryConstructorInitialization(S, Entity, Kind, 0, 0, DestType, Sequence); } @@ -2661,7 +2661,7 @@ static void TryDefaultInitialization(Sema &S, // If a program calls for the default initialization of an object of // a const-qualified type T, T shall be a class type with a user-provided // default constructor. - if (DestType.isConstQualified()) + if (DestType.isConstQualified() && S.getLangOptions().CPlusPlus) Sequence.SetFailed(InitializationSequence::FK_DefaultInitOfConst); } diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index d7820bbc2e..08cb681960 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -217,6 +217,8 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) { // FIXME: having to fake up a LookupResult is dumb. LookupResult Previous(SemaRef, Var->getDeclName(), Var->getLocation(), Sema::LookupOrdinaryName); + if (D->isStaticDataMember()) + SemaRef.LookupQualifiedName(Previous, Owner, false); SemaRef.CheckVariableDeclaration(Var, Previous, Redeclaration); if (D->isOutOfLine()) { @@ -232,7 +234,9 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) { SemaRef.Context.setInstantiatedFromStaticDataMember(Var, D, TSK_ImplicitInstantiation); - if (D->getInit()) { + if (Var->getAnyInitializer()) { + // We already have an initializer in the class. + } else if (D->getInit()) { if (Var->isStaticDataMember() && !D->isOutOfLine()) SemaRef.PushExpressionEvaluationContext(Sema::Unevaluated); else @@ -1821,7 +1825,6 @@ void Sema::InstantiateStaticDataMemberDefinition( CurContext = PreviousContext; if (Var) { - Var->setPreviousDeclaration(OldVar); MemberSpecializationInfo *MSInfo = OldVar->getMemberSpecializationInfo(); assert(MSInfo && "Missing member specialization information?"); Var->setTemplateSpecializationKind(MSInfo->getTemplateSpecializationKind(), diff --git a/test/CXX/dcl.decl/dcl.init/p6.cpp b/test/CXX/dcl.decl/dcl.init/p6.cpp index 370bafcfbd..f627a199ec 100644 --- a/test/CXX/dcl.decl/dcl.init/p6.cpp +++ b/test/CXX/dcl.decl/dcl.init/p6.cpp @@ -11,5 +11,5 @@ struct HasUserDefault { HasUserDefault(); }; void test_const_default_init() { const NoUserDefault x1; // expected-error{{default initialization of an object of const type 'struct NoUserDefault const' requires a user-provided default constructor}} const HasUserDefault x2; - const int x3; // FIXME: xpected-error{{default initialization of an object of const type 'struct NoUserDefault const' requires a user-provided default constructor}} + const int x3; // expected-error{{default initialization of an object of const type 'int const'}} } diff --git a/test/CXX/expr/p8.cpp b/test/CXX/expr/p8.cpp index cc834d9dc8..2f6c094301 100644 --- a/test/CXX/expr/p8.cpp +++ b/test/CXX/expr/p8.cpp @@ -1,7 +1,7 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s int a0; -const volatile int a1; +const volatile int a1 = 2; int a2[16]; int a3(); diff --git a/test/CXX/temp/temp.decls/temp.mem/p5.cpp b/test/CXX/temp/temp.decls/temp.mem/p5.cpp index 098ffa4dec..b0078d4bdb 100644 --- a/test/CXX/temp/temp.decls/temp.mem/p5.cpp +++ b/test/CXX/temp/temp.decls/temp.mem/p5.cpp @@ -55,7 +55,7 @@ template double Foo::As2(); // Partial ordering with conversion function templates. struct X0 { template<typename T> operator T*() { - T x; + T x = 1; x = 17; // expected-error{{read-only variable is not assignable}} } diff --git a/test/Sema/incomplete-decl.c b/test/Sema/incomplete-decl.c index 753d9c0a3c..e5b6d5f0da 100644 --- a/test/Sema/incomplete-decl.c +++ b/test/Sema/incomplete-decl.c @@ -16,7 +16,7 @@ int ary[]; // expected-warning {{tentative array definition assumed to have one struct foo bary[]; // expected-error {{array has incomplete element type 'struct foo'}} void func() { - int ary[]; // expected-error{{variable has incomplete type 'int []'}} + int ary[]; // expected-error{{definition of variable with array type needs an explicit size or an initializer}} void b; // expected-error {{variable has incomplete type 'void'}} struct foo f; // expected-error {{variable has incomplete type 'struct foo'}} } diff --git a/test/SemaCXX/cast-conversion.cpp b/test/SemaCXX/cast-conversion.cpp index 77f4a52890..074e133040 100644 --- a/test/SemaCXX/cast-conversion.cpp +++ b/test/SemaCXX/cast-conversion.cpp @@ -30,7 +30,7 @@ X0<T> make_X0(const T &Val) { } void test_X0() { - const char array[2]; + const char array[2] = { 'a', 'b' }; make_X0(array); } diff --git a/test/SemaCXX/dcl_ambig_res.cpp b/test/SemaCXX/dcl_ambig_res.cpp index 859d2045da..f0ba2978e8 100644 --- a/test/SemaCXX/dcl_ambig_res.cpp +++ b/test/SemaCXX/dcl_ambig_res.cpp @@ -12,8 +12,8 @@ void foo(double a) { S w(int(a)); // expected-warning{{disambiguated}} w(17); - S x(int()); // expected-warning{{disambiguated}} - x(&returns_an_int); + S x1(int()); // expected-warning{{disambiguated}} + x1(&returns_an_int); S y((int)a); y.bar(); S z = int(a); diff --git a/test/SemaTemplate/instantiate-declref-ice.cpp b/test/SemaTemplate/instantiate-declref-ice.cpp index e4e071dd20..e88b49447c 100644 --- a/test/SemaTemplate/instantiate-declref-ice.cpp +++ b/test/SemaTemplate/instantiate-declref-ice.cpp @@ -1,5 +1,4 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s - template<int i> struct x { static const int j = i; x<j>* y; @@ -10,7 +9,6 @@ const int x<i>::j; int array0[x<2>::j]; - template<typename T> struct X0 { static const unsigned value = sizeof(T); diff --git a/test/SemaTemplate/instantiate-expr-4.cpp b/test/SemaTemplate/instantiate-expr-4.cpp index b5ffa4b39b..c5eb3cc53e 100644 --- a/test/SemaTemplate/instantiate-expr-4.cpp +++ b/test/SemaTemplate/instantiate-expr-4.cpp @@ -173,8 +173,8 @@ struct is_pod { static const bool value = __is_pod(T); }; -static const int is_pod0[is_pod<X>::value? -1 : 1]; -static const int is_pod1[is_pod<Y>::value? 1 : -1]; +static int is_pod0[is_pod<X>::value? -1 : 1]; +static int is_pod1[is_pod<Y>::value? 1 : -1]; // --------------------------------------------------------------------- // initializer lists |