More semantic analysis of initializers.
Added 2 errors and one warning, updated test case. llvm-svn: 41672
This commit is contained in:
parent
2fea13926f
commit
f33527a1aa
|
@ -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
|
||||
|
|
|
@ -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...
|
||||
|
|
|
@ -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'")
|
||||
|
|
|
@ -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}}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue