diff options
-rw-r--r-- | clang/Sema/Sema.h | 5 | ||||
-rw-r--r-- | clang/Sema/SemaDecl.cpp | 41 | ||||
-rw-r--r-- | clang/include/clang/Basic/DiagnosticKinds.def | 6 | ||||
-rw-r--r-- | clang/test/Sema/array-init.c | 9 |
4 files changed, 58 insertions, 3 deletions
diff --git a/clang/Sema/Sema.h b/clang/Sema/Sema.h index e99e332cf5a..38c11a014aa 100644 --- a/clang/Sema/Sema.h +++ b/clang/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/clang/Sema/SemaDecl.cpp b/clang/Sema/SemaDecl.cpp index 6d8308a882f..5eac6457277 100644 --- a/clang/Sema/SemaDecl.cpp +++ b/clang/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<InitListExpr>(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<InitListExpr>(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/clang/include/clang/Basic/DiagnosticKinds.def b/clang/include/clang/Basic/DiagnosticKinds.def index 0eb3da260a3..5de34aa774a 100644 --- a/clang/include/clang/Basic/DiagnosticKinds.def +++ b/clang/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/clang/test/Sema/array-init.c b/clang/test/Sema/array-init.c index 2a26103a317..3ab2f4e5781 100644 --- a/clang/test/Sema/array-init.c +++ b/clang/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}} } |