From: Steve Naroff Date: Sun, 2 Sep 2007 15:34:30 +0000 (+0000) Subject: More semantic analysis of initializers. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=6f9f307d527e3451470dd07ae932475f26c6de6e;p=clang More semantic analysis of initializers. Added 2 errors and one warning, updated test case. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@41672 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/Sema/Sema.h b/Sema/Sema.h index e99e332cf5..38c11a014a 100644 --- a/Sema/Sema.h +++ b/Sema/Sema.h @@ -30,6 +30,7 @@ namespace clang { class Preprocessor; class Decl; class Expr; + class InitListExpr; class VarDecl; class ParmVarDecl; class TypedefDecl; @@ -441,8 +442,10 @@ private: IdentifierInfo &Comp, SourceLocation CmpLoc); /// type checking declaration initializers (C99 6.7.8) - QualType CheckInitializer(Expr *simpleInit_or_initList, QualType declType); + QualType CheckInitializer(Expr *simpleInit_or_initList, QualType declType, + bool isStatic); bool CheckSingleInitializer(Expr *simpleInit, QualType declType); + bool RequireConstantExprs(InitListExpr *IList); /// ConvertIntegerToTypeWarnOnOverflow - Convert the specified APInt to have /// the specified width and sign. If an overflow occurs, detect it and emit diff --git a/Sema/SemaDecl.cpp b/Sema/SemaDecl.cpp index 6d8308a882..5eac645727 100644 --- a/Sema/SemaDecl.cpp +++ b/Sema/SemaDecl.cpp @@ -253,6 +253,10 @@ bool Sema::CheckSingleInitializer(Expr *Init, QualType DeclType) { case Compatible: break; case Incompatible: + // FIXME: tighten up this check which should allow: + // char s[] = "abc", which is identical to char s[] = { 'a', 'b', 'c' }; + if (rhsType == Context.getPointerType(Context.CharTy)) + break; Diag(loc, diag::err_typecheck_assign_incompatible, DeclType.getAsString(), rhsType.getAsString(), Init->getSourceRange()); @@ -285,13 +289,36 @@ bool Sema::CheckSingleInitializer(Expr *Init, QualType DeclType) { return false; } -QualType Sema::CheckInitializer(Expr *Init, QualType DeclType) { +bool Sema::RequireConstantExprs(InitListExpr *IList) { + bool hadError = false; + for (unsigned i = 0; i < IList->getNumInits(); i++) { + Expr *expr = IList->getInit(i); + + if (InitListExpr *InitList = dyn_cast(expr)) + RequireConstantExprs(InitList); + else { + SourceLocation loc; + // FIXME: should be isConstantExpr()... + if (!expr->isIntegerConstantExpr(Context, &loc)) { + Diag(loc, diag::err_init_element_not_constant, expr->getSourceRange()); + hadError = true; + } + } + } + return hadError; +} + +QualType Sema::CheckInitializer(Expr *Init, QualType DeclType, bool isStatic) { InitListExpr *InitList = dyn_cast(Init); if (!InitList) { return CheckSingleInitializer(Init, DeclType) ? QualType() : DeclType; } // We have an InitListExpr, make sure we set the type. Init->setType(DeclType); + + if (isStatic) // C99 6.7.8p4. + RequireConstantExprs(InitList); + // FIXME: Lot of checking still to do... return DeclType; } @@ -395,6 +422,11 @@ Sema::ParseDeclarator(Scope *S, Declarator &D, ExprTy *init, case DeclSpec::SCS_register: SC = VarDecl::Register; break; } if (S->getParent() == 0) { + if (Init) { + if (SC == VarDecl::Extern) + Diag(D.getIdentifierLoc(), diag::warn_extern_init); + CheckInitializer(Init, R, true); + } // File scope. C99 6.9.2p2: A declaration of an identifier for and // object that has file scope without an initializer, and without a // storage-class specifier or with the storage-class specifier "static", @@ -434,7 +466,12 @@ Sema::ParseDeclarator(Scope *S, Declarator &D, ExprTy *init, NewVD = new FileVarDecl(D.getIdentifierLoc(), II, R, SC, LastDeclarator); } else { if (Init) { - CheckInitializer(Init, R); + if (SC == VarDecl::Extern) { // C99 6.7.8p5 + Diag(D.getIdentifierLoc(), diag::err_block_extern_cant_init); + InvalidDecl = true; + } else { + CheckInitializer(Init, R, SC == VarDecl::Static); + } } // 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... diff --git a/include/clang/Basic/DiagnosticKinds.def b/include/clang/Basic/DiagnosticKinds.def index 0eb3da260a..5de34aa774 100644 --- a/include/clang/Basic/DiagnosticKinds.def +++ b/include/clang/Basic/DiagnosticKinds.def @@ -542,6 +542,12 @@ DIAG(ext_typecheck_zero_array_size, EXTENSION, "zero size arrays are an extension") DIAG(err_array_size_non_int, ERROR, "size of array has non-integer type '%0'") +DIAG(err_init_element_not_constant, ERROR, + "initializer element is not constant") +DIAG(err_block_extern_cant_init, ERROR, + "'extern' variable cannot have an initializer") +DIAG(warn_extern_init, WARNING, + "'extern' variable has an initializer") DIAG(err_redefinition_of_label, ERROR, "redefinition of label '%0'") diff --git a/test/Sema/array-init.c b/test/Sema/array-init.c index 2a26103a31..3ab2f4e578 100644 --- a/test/Sema/array-init.c +++ b/test/Sema/array-init.c @@ -1,5 +1,12 @@ // RUN: clang -parse-ast-check -pedantic %s +static int x, y, z; + +static int ary[] = { x, y, z }; // expected-error{{initializer element is not constant}} +int ary2[] = { x, y, z }; // expected-error{{initializer element is not constant}} + +extern int fileScopeExtern[3] = { 1, 3, 5 }; // expected-warning{{'extern' variable has an initializer}} + void func() { int x = 1; @@ -24,4 +31,6 @@ void func() { } z = { 1 }; struct threeElements *p = 7; // expected-warning{{incompatible types assigning 'int' to 'struct threeElements *'}} + + extern int blockScopeExtern[3] = { 1, 3, 5 }; // expected-error{{'extern' variable cannot have an initializer}} }