More semantic analysis of initializers.

Added 2 errors and one warning, updated test case.

llvm-svn: 41672
This commit is contained in:
Steve Naroff 2007-09-02 15:34:30 +00:00
parent 2fea13926f
commit f33527a1aa
4 changed files with 58 additions and 3 deletions

View File

@ -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

View File

@ -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...

View File

@ -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'")

View File

@ -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}}
}