]> granicus.if.org Git - clang/commitdiff
Add support for initializing char arrays from string literals.
authorSteve Naroff <snaroff@apple.com>
Mon, 10 Dec 2007 22:44:33 +0000 (22:44 +0000)
committerSteve Naroff <snaroff@apple.com>
Mon, 10 Dec 2007 22:44:33 +0000 (22:44 +0000)
Adapted from a patch by Anders Carlsson.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@44816 91177308-0d34-0410-b5e6-96231b3b80d8

Sema/Sema.h
Sema/SemaDecl.cpp
Sema/SemaExpr.cpp
include/clang/Basic/DiagnosticKinds.def
test/Sema/array-constraint.c
test/Sema/array-init.c

index 234fc157d878fdc2f4e817676e21d96e61f53fb3..4c9f4788f8e2d2687cd0c4495bd0f4810c016517 100644 (file)
@@ -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.
index 23a4e67884f9cc55ecb664bd31ec955bb41113ec..1290975a24b0b315758f155484ad644b8f8c008a 100644 (file)
@@ -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<InitListExpr>(expr)) {
-      if (const ConstantArrayType *CAT = DeclType->getAsConstantArrayType()) {
-        int maxElements = CAT->getMaximumElements();
-        CheckConstantInitList(DeclType, InitList, ElementType, isStatic, 
-                              maxElements, hadError);
+      if (InitListExpr *InitList = dyn_cast<InitListExpr>(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<StringLiteral>(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) {
+  bool hadError = false;
+  
   InitListExpr *InitList = dyn_cast<InitListExpr>(Init);
-  if (!InitList)
+  if (!InitList) {
+    if (StringLiteral *strLiteral = dyn_cast<StringLiteral>(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()) {
index 3fa159eb4463ad25aeb8cfea08ac48cd9eeb0b30..5cf2745c98010db65a5f95284ca5a482c6cd2980 100644 (file)
@@ -689,15 +689,9 @@ ActOnCompoundLiteral(SourceLocation LParenLoc, TypeTy *Ty,
   //assert((InitExpr != 0) && "ActOnCompoundLiteral(): missing expression");
   Expr *literalExpr = static_cast<Expr*>(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);
 }
index e37262f93eb5df784a5122018ffabbe5e1d9cc9b..e2be35f317a7018415ae822639f848c3c02f9d1d 100644 (file)
@@ -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,
index ab2c969434df7378ff8e7378858b1d790da6f946..f281df1aff29339bc0b71ea2c0cfad9ed2aa0d16 100644 (file)
@@ -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}}
 }
 
 
index 5b22681d1b9e084abe899808001cbccf480b3f93..bf5ea06bab4a6b3545bf8b6f3c9c3638c2098477 100644 (file)
@@ -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}}
+}
+