diff --git a/Sema/Sema.h b/Sema/Sema.h index 234fc157d8..4c9f4788f8 100644 --- a/Sema/Sema.h +++ b/Sema/Sema.h @@ -684,7 +684,10 @@ private: void CheckConstantInitList(QualType DeclType, InitListExpr *IList, QualType ElementType, bool isStatic, int &nInitializers, bool &hadError); - + bool CheckForCharArrayInitializer(InitListExpr *IList, QualType ElementType, + int &nInitializers, bool isConstant, + bool &hadError); + // CheckVectorCast - check type constraints for vectors. // Since vectors are an extension, there are no C standard reference for this. // We allow casting between vectors and integer datatypes of the same size. diff --git a/Sema/SemaDecl.cpp b/Sema/SemaDecl.cpp index 23a4e67884..1290975a24 100644 --- a/Sema/SemaDecl.cpp +++ b/Sema/SemaDecl.cpp @@ -429,21 +429,75 @@ bool Sema::CheckInitExpr(Expr *expr, InitListExpr *IList, unsigned slot, void Sema::CheckVariableInitList(QualType DeclType, InitListExpr *IList, QualType ElementType, bool isStatic, int &nInitializers, bool &hadError) { - for (unsigned i = 0; i < IList->getNumInits(); i++) { - Expr *expr = IList->getInit(i); + unsigned numInits = IList->getNumInits(); + + if (numInits) { + if (CheckForCharArrayInitializer(IList, ElementType, nInitializers, + false, hadError)) + return; + + for (unsigned i = 0; i < numInits; i++) { + Expr *expr = IList->getInit(i); - if (InitListExpr *InitList = dyn_cast(expr)) { - if (const ConstantArrayType *CAT = DeclType->getAsConstantArrayType()) { - int maxElements = CAT->getMaximumElements(); - CheckConstantInitList(DeclType, InitList, ElementType, isStatic, - maxElements, hadError); + if (InitListExpr *InitList = dyn_cast(expr)) { + if (const ConstantArrayType *CAT = DeclType->getAsConstantArrayType()) { + int maxElements = CAT->getMaximumElements(); + CheckConstantInitList(DeclType, InitList, ElementType, isStatic, + maxElements, hadError); + } + } else { + hadError = CheckInitExpr(expr, IList, i, isStatic, ElementType); + } + nInitializers++; + } + } else { + Diag(IList->getLocStart(), + diag::err_at_least_one_initializer_needed_to_size_array); + hadError = true; + } +} + +bool Sema::CheckForCharArrayInitializer(InitListExpr *IList, + QualType ElementType, + int &nInitializers, bool isConstant, + bool &hadError) +{ + if (ElementType->isPointerType()) + return false; + + if (StringLiteral *literal = dyn_cast(IList->getInit(0))) { + // FIXME: Handle wide strings + if (ElementType->isCharType()) { + if (isConstant) { + if (literal->getByteLength() > (unsigned)nInitializers) { + Diag(literal->getSourceRange().getBegin(), + diag::warn_initializer_string_for_char_array_too_long, + literal->getSourceRange()); + } + } else { + nInitializers = literal->getByteLength() + 1; } } else { - hadError = CheckInitExpr(expr, IList, i, isStatic, ElementType); + // FIXME: It might be better if we could point to the declaration + // here, instead of the string literal. + Diag(literal->getSourceRange().getBegin(), + diag::array_of_wrong_type_initialized_from_string, + ElementType.getAsString()); + hadError = true; } - nInitializers++; + + // Check for excess initializers + for (unsigned i = 1; i < IList->getNumInits(); i++) { + Expr *expr = IList->getInit(i); + Diag(expr->getLocStart(), + diag::err_excess_initializers_in_char_array_initializer, + expr->getSourceRange()); + } + + return true; } - return; + + return false; } // FIXME: Doesn't deal with arrays of structures yet. @@ -473,6 +527,11 @@ void Sema::CheckConstantInitList(QualType DeclType, InitListExpr *IList, // The empty init list "{ }" is treated specially below. unsigned numInits = IList->getNumInits(); if (numInits) { + if (CheckForCharArrayInitializer(IList, ElementType, + maxElementsAtThisLevel, + true, hadError)) + return; + for (unsigned i = 0; i < numInits; i++) { Expr *expr = IList->getInit(i); @@ -499,19 +558,42 @@ void Sema::CheckConstantInitList(QualType DeclType, InitListExpr *IList, Diag(IList->getLocStart(), diag::warn_excess_initializers, IList->getSourceRange()); } - return; } bool Sema::CheckInitializer(Expr *&Init, QualType &DeclType, bool isStatic) { - InitListExpr *InitList = dyn_cast(Init); - if (!InitList) - return CheckSingleInitializer(Init, isStatic, DeclType); + bool hadError = false; + InitListExpr *InitList = dyn_cast(Init); + if (!InitList) { + if (StringLiteral *strLiteral = dyn_cast(Init)) { + const VariableArrayType *VAT = DeclType->getAsVariableArrayType(); + // FIXME: Handle wide strings + if (VAT && VAT->getElementType()->isCharType()) { + // C99 6.7.8p14. We have an array of character type with unknown size + // being initialized to a string literal. + llvm::APSInt ConstVal(32); + ConstVal = strLiteral->getByteLength() + 1; + // Return a new array type (C99 6.7.8p22). + DeclType = Context.getConstantArrayType(VAT->getElementType(), ConstVal, + ArrayType::Normal, 0); + return hadError; + } + const ConstantArrayType *CAT = DeclType->getAsConstantArrayType(); + if (CAT && CAT->getElementType()->isCharType()) { + // C99 6.7.8p14. We have an array of character type with known size. + if (strLiteral->getByteLength() > (unsigned)CAT->getMaximumElements()) { + Diag(strLiteral->getSourceRange().getBegin(), + diag::warn_initializer_string_for_char_array_too_long, + strLiteral->getSourceRange()); + } + return hadError; + } + } + return CheckSingleInitializer(Init, isStatic, DeclType); + } // We have an InitListExpr, make sure we set the type. Init->setType(DeclType); - bool hadError = false; - // 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()) { @@ -525,13 +607,19 @@ bool Sema::CheckInitializer(Expr *&Init, QualType &DeclType, bool isStatic) { int numInits = 0; CheckVariableInitList(VAT->getElementType(), InitList, VAT->getBaseType(), isStatic, numInits, hadError); - if (!hadError) { - // Return a new array type from the number of initializers (C99 6.7.8p22). - llvm::APSInt ConstVal(32); + llvm::APSInt ConstVal(32); + + if (!hadError) ConstVal = numInits; - DeclType = Context.getConstantArrayType(VAT->getElementType(), ConstVal, - ArrayType::Normal, 0); - } + + // Return a new array type from the number of initializers (C99 6.7.8p22). + + // Note that if there was an error, we will still set the decl type, + // to an array type with 0 elements. + // This is to avoid "incomplete type foo[]" errors when we've already + // reported the real cause of the error. + DeclType = Context.getConstantArrayType(VAT->getElementType(), ConstVal, + ArrayType::Normal, 0); return hadError; } if (const ConstantArrayType *CAT = DeclType->getAsConstantArrayType()) { diff --git a/Sema/SemaExpr.cpp b/Sema/SemaExpr.cpp index 3fa159eb44..5cf2745c98 100644 --- a/Sema/SemaExpr.cpp +++ b/Sema/SemaExpr.cpp @@ -689,15 +689,9 @@ ActOnCompoundLiteral(SourceLocation LParenLoc, TypeTy *Ty, //assert((InitExpr != 0) && "ActOnCompoundLiteral(): missing expression"); Expr *literalExpr = static_cast(InitExpr); - // FIXME: This is just a temporary workaround to get - // test/Parser/compound_literal.c passing. (CheckInitializer does not support - // initializing a char array from a single string literal). - if (!literalType->isArrayType() || - !literalType->getAsArrayType()->getElementType()->isCharType()) { - // FIXME: add more semantic analysis (C99 6.5.2.5). - if (CheckInitializer(literalExpr, literalType, false)) - return 0; - } + // FIXME: add more semantic analysis (C99 6.5.2.5). + if (CheckInitializer(literalExpr, literalType, false)) + return 0; return new CompoundLiteralExpr(literalType, literalExpr); } diff --git a/include/clang/Basic/DiagnosticKinds.def b/include/clang/Basic/DiagnosticKinds.def index e37262f93e..e2be35f317 100644 --- a/include/clang/Basic/DiagnosticKinds.def +++ b/include/clang/Basic/DiagnosticKinds.def @@ -605,6 +605,10 @@ DIAG(err_typecheck_negative_array_size, ERROR, "array size is negative") DIAG(ext_typecheck_zero_array_size, EXTENSION, "zero size arrays are an extension") +DIAG(err_at_least_one_initializer_needed_to_size_array, ERROR, + "at least one initializer value required to size array") +DIAG(array_of_wrong_type_initialized_from_string, ERROR, + "array of wrong type '%0' initialized from string constant") DIAG(err_array_size_non_int, ERROR, "size of array has non-integer type '%0'") DIAG(err_init_element_not_constant, ERROR, @@ -617,6 +621,10 @@ DIAG(err_variable_object_no_init, ERROR, "variable-sized object may not be initialized") DIAG(warn_excess_initializers, EXTENSION, "excess elements in array initializer") +DIAG(err_excess_initializers_in_char_array_initializer, ERROR, + "excess elements in char array initializer") +DIAG(warn_initializer_string_for_char_array_too_long, WARNING, + "initializer-string for char array is too long") DIAG(warn_braces_around_scalar_init, WARNING, "braces around scalar initializer") DIAG(err_illegal_initializer, ERROR, diff --git a/test/Sema/array-constraint.c b/test/Sema/array-constraint.c index ab2c969434..f281df1aff 100644 --- a/test/Sema/array-constraint.c +++ b/test/Sema/array-constraint.c @@ -45,7 +45,7 @@ typedef int TA[I]; // expected-error {{variable length array declared outside of void strFunc(char *); const char staticAry[] = "test"; int checkStaticAry() { - strFunc(staticAry); // expected-warning{{passing 'char const []' to 'char *' discards qualifiers}} + strFunc(staticAry); // expected-warning{{passing 'char const [5]' to 'char *' discards qualifiers}} } diff --git a/test/Sema/array-init.c b/test/Sema/array-init.c index 5b22681d1b..bf5ea06bab 100644 --- a/test/Sema/array-init.c +++ b/test/Sema/array-init.c @@ -137,3 +137,28 @@ void testTypedef() AryT a = { 1, 2 }, b = { 3, 4, 5 }; } +static char const xx[] = "test"; +static char const yy[5] = "test"; +static char const zz[3] = "test"; // expected-warning{{initializer-string for char array is too long}} + +void charArrays() +{ + static char const test[] = "test"; + static char const test2[] = { "weird stuff" }; + static char const test3[] = { "test", "excess stuff" }; // expected-error{{excess elements in char array initializer}} + + char* cp[] = { "Hello" }; + + char c[] = { "Hello" }; + int l[sizeof(c) == 6 ? 1 : -1]; + + int i[] = { "Hello "}; // expected-error{{array of wrong type 'int' initialized from string constant}} + char c2[] = { "Hello", "Good bye" }; //expected-error{{excess elements in char array initializer}} + + int i2[1] = { "Hello" }; //expected-error{{array of wrong type 'int' initialized from string constant}} + char c3[5] = { "Hello" }; + char c4[4] = { "Hello" }; //expected-warning{{initializer-string for char array is too long}} + + int i3[] = {}; //expected-error{{at least one initializer value required to size array}} expected-warning{{use of GNU empty initializer extension}} +} +