aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Sema/Sema.h7
-rw-r--r--Sema/SemaDecl.cpp76
-rw-r--r--Sema/SemaExpr.cpp6
-rw-r--r--include/clang/Basic/DiagnosticKinds.def2
-rw-r--r--test/Sema/array-init.c14
5 files changed, 73 insertions, 32 deletions
diff --git a/Sema/Sema.h b/Sema/Sema.h
index a741657bf6..0979c607a0 100644
--- a/Sema/Sema.h
+++ b/Sema/Sema.h
@@ -442,10 +442,11 @@ private:
IdentifierInfo &Comp, SourceLocation CmpLoc);
/// type checking declaration initializers (C99 6.7.8)
- QualType CheckInitializer(Expr *simpleInit_or_initList, QualType declType,
- bool isStatic);
+ bool CheckInitializer(Expr *simpleInit_or_initList, QualType &declType,
+ bool isStatic);
bool CheckSingleInitializer(Expr *simpleInit, QualType declType);
- bool CheckInitList(InitListExpr *IList, QualType DType, bool isStatic);
+ void CheckInitList(InitListExpr *IList, QualType DType, bool isStatic,
+ int &nInitializers, int maxElements, bool &hadError);
/// 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 c2f03a373c..15fe7c1033 100644
--- a/Sema/SemaDecl.cpp
+++ b/Sema/SemaDecl.cpp
@@ -289,15 +289,17 @@ bool Sema::CheckSingleInitializer(Expr *Init, QualType DeclType) {
return false;
}
-bool Sema::CheckInitList(InitListExpr *IList, QualType DType, bool isStatic) {
- bool hadError = false;
+void Sema::CheckInitList(InitListExpr *IList, QualType DType,
+ bool isStatic, int &nInitializers, int maxElements,
+ bool &hadError) {
for (unsigned i = 0; i < IList->getNumInits(); i++) {
Expr *expr = IList->getInit(i);
if (InitListExpr *InitList = dyn_cast<InitListExpr>(expr))
- CheckInitList(InitList, DType, isStatic);
+ CheckInitList(InitList, DType, isStatic, nInitializers, maxElements,
+ hadError);
else {
- SourceLocation loc;
+ SourceLocation loc = expr->getLocStart();
if (isStatic && !expr->isConstantExpr(Context, &loc)) { // C99 6.7.8p4.
Diag(loc, diag::err_init_element_not_constant, expr->getSourceRange());
@@ -305,41 +307,71 @@ bool Sema::CheckInitList(InitListExpr *IList, QualType DType, bool isStatic) {
} else if (CheckSingleInitializer(expr, DType)) {
hadError = true; // types didn't match.
}
+ // Does the element fit?
+ nInitializers++;
+ if ((maxElements >= 0) && (nInitializers > maxElements))
+ Diag(loc, diag::warn_excess_initializers, expr->getSourceRange());
}
}
- return hadError;
+ return;
}
-QualType Sema::CheckInitializer(Expr *Init, QualType DeclType, bool isStatic) {
+bool Sema::CheckInitializer(Expr *Init, QualType &DeclType, bool isStatic) {
InitListExpr *InitList = dyn_cast<InitListExpr>(Init);
- if (!InitList) {
- return CheckSingleInitializer(Init, DeclType) ? QualType() : DeclType;
- }
+ if (!InitList)
+ return CheckSingleInitializer(Init, DeclType);
+
// We have an InitListExpr, make sure we set the type.
Init->setType(DeclType);
+
+ bool hadError = false;
+ int nInits = 0;
// C99 6.7.8p3: The type of the entity to be initialized shall be an array
// of unknown size ("[]") or an object type that is not a variable array type.
if (const VariableArrayType *VAT = DeclType->getAsVariableArrayType()) {
Expr *expr = VAT->getSizeExpr();
- if (expr) {
- Diag(expr->getLocStart(), diag::err_variable_object_no_init,
- expr->getSourceRange());
- return QualType();
+ if (expr)
+ return Diag(expr->getLocStart(), diag::err_variable_object_no_init,
+ expr->getSourceRange());
+
+ // We have a VariableArrayType with unknown size.
+ QualType ElmtType = VAT->getElementType();
+
+ // If we have a multi-dimensional array, navigate to the base type.
+ while ((VAT = ElmtType->getAsVariableArrayType())) {
+ ElmtType = VAT->getElementType();
+ }
+ CheckInitList(InitList, ElmtType, isStatic, nInits, -1, hadError);
+
+ if (!hadError) {
+ // Return a new array type from the number of initializers (C99 6.7.8p22).
+ llvm::APSInt ConstVal(32);
+ ConstVal = nInits;
+ DeclType = Context.getConstantArrayType(ElmtType, ConstVal,
+ ArrayType::Normal, 0);
}
+ return hadError;
}
- if (const ArrayType *Ary = DeclType->getAsArrayType()) {
- // We have a ConstantArrayType or VariableArrayType with unknown size.
- QualType ElmtType = Ary->getElementType();
+ if (const ConstantArrayType *CAT = DeclType->getAsConstantArrayType()) {
+ QualType ElmtType = CAT->getElementType();
+ unsigned numElements = CAT->getSize().getZExtValue();
- // If we have a multi-dimensional array, navigate to the base type.
- while ((Ary = ElmtType->getAsArrayType()))
- ElmtType = Ary->getElementType();
-
- CheckInitList(InitList, ElmtType, isStatic);
+ // If we have a multi-dimensional array, navigate to the base type. Also
+ // compute the absolute size of the array, so we can detect excess elements.
+ while ((CAT = ElmtType->getAsConstantArrayType())) {
+ ElmtType = CAT->getElementType();
+ numElements *= CAT->getSize().getZExtValue();
+ }
+ CheckInitList(InitList, ElmtType, isStatic, nInits, numElements, hadError);
+ return hadError;
+ }
+ if (DeclType->isScalarType()) { // C99 6.7.8p11
+ CheckInitList(InitList, DeclType, isStatic, nInits, 1, hadError);
+ return hadError;
}
// FIXME: Handle struct/union types.
- return DeclType;
+ return hadError;
}
Sema::DeclTy *
diff --git a/Sema/SemaExpr.cpp b/Sema/SemaExpr.cpp
index 8788c2f9dc..55b6d600c4 100644
--- a/Sema/SemaExpr.cpp
+++ b/Sema/SemaExpr.cpp
@@ -644,10 +644,8 @@ ParseInitList(SourceLocation LBraceLoc, ExprTy **initlist, unsigned NumInit,
SourceLocation RBraceLoc) {
Expr **InitList = reinterpret_cast<Expr**>(initlist);
- // FIXME: add semantic analysis (C99 6.7.8). This involves
- // knowledge of the object being intialized. As a result, the code for
- // doing the semantic analysis will likely be located elsewhere (i.e. in
- // consumers of InitListExpr (e.g. ParseDeclarator, ParseCompoundLiteral).
+ // Semantic analysis for initializers is done by ParseDeclarator() and
+ // CheckInitializer() - it requires knowledge of the object being intialized.
InitListExpr *e = new InitListExpr(LBraceLoc, InitList, NumInit, RBraceLoc);
e->setType(Context.VoidTy); // FIXME: just a place holder for now.
diff --git a/include/clang/Basic/DiagnosticKinds.def b/include/clang/Basic/DiagnosticKinds.def
index e396d95b55..85ed51bd79 100644
--- a/include/clang/Basic/DiagnosticKinds.def
+++ b/include/clang/Basic/DiagnosticKinds.def
@@ -550,6 +550,8 @@ DIAG(warn_extern_init, WARNING,
"'extern' variable has an initializer")
DIAG(err_variable_object_no_init, ERROR,
"variable-sized object may not be initialized")
+DIAG(warn_excess_initializers, WARNING,
+ "excess elements in array 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 209b73463a..20daa45838 100644
--- a/test/Sema/array-init.c
+++ b/test/Sema/array-init.c
@@ -7,16 +7,16 @@ 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}}
-static int ary3[] = { 1, "abc", 3 }; // expected-warning{{incompatible types assigning 'char *' to 'int'}}
+static int ary3[] = { 1, "abc", 3, 4 }; // expected-warning{{incompatible types assigning 'char *' to 'int'}}
void func() {
int x = 1;
- //int x2[] = { 1, 3, 5 };
+ int xComputeSize[] = { 1, 3, 5 };
int x3[x] = { 1, 2 }; // expected-error{{variable-sized object may not be initialized}}
- int x4 = { 1, 2 }; // gcc-warning {{excess elements in array initializer}}
+ int x4 = { 1, 2 }; // // expected-warning{{excess elements in array initializer}}
int y[4][3] = {
{ 1, 3, 5 },
@@ -28,6 +28,14 @@ void func() {
1, 3, 5, 2, 4, 6, 3, 5, 7
};
+ int y3[4][3] = {
+ { 1, 3, 5 },
+ { 2, 4, 6 },
+ { 3, 5, 7 },
+ { 4, 6, 8 },
+ { 5 }, // expected-warning{{excess elements in array initializer}}
+ };
+
struct threeElements {
int a,b,c;
} z = { 1 };