[cfe-commits] r44816 - in /cfe/trunk: Sema/Sema.h Sema/SemaDecl.cpp Sema/SemaExpr.cpp include/clang/Basic/DiagnosticKinds.def test/Sema/array-constraint.c test/Sema/array-init.c

Steve Naroff snaroff at apple.com
Mon Dec 10 14:44:33 PST 2007


Author: snaroff
Date: Mon Dec 10 16:44:33 2007
New Revision: 44816

URL: http://llvm.org/viewvc/llvm-project?rev=44816&view=rev
Log:

Add support for initializing char arrays from string literals.

Adapted from a patch by Anders Carlsson.


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

Modified: cfe/trunk/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/Sema/Sema.h?rev=44816&r1=44815&r2=44816&view=diff

==============================================================================
--- cfe/trunk/Sema/Sema.h (original)
+++ cfe/trunk/Sema/Sema.h Mon Dec 10 16:44:33 2007
@@ -684,7 +684,10 @@
   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.

Modified: cfe/trunk/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/Sema/SemaDecl.cpp?rev=44816&r1=44815&r2=44816&view=diff

==============================================================================
--- cfe/trunk/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/Sema/SemaDecl.cpp Mon Dec 10 16:44:33 2007
@@ -429,21 +429,75 @@
 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 @@
   // 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 @@
       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 @@
     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()) {

Modified: cfe/trunk/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/Sema/SemaExpr.cpp?rev=44816&r1=44815&r2=44816&view=diff

==============================================================================
--- cfe/trunk/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/Sema/SemaExpr.cpp Mon Dec 10 16:44:33 2007
@@ -689,15 +689,9 @@
   //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);
 }

Modified: cfe/trunk/include/clang/Basic/DiagnosticKinds.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticKinds.def?rev=44816&r1=44815&r2=44816&view=diff

==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticKinds.def (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticKinds.def Mon Dec 10 16:44:33 2007
@@ -605,6 +605,10 @@
      "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 @@
      "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,

Modified: cfe/trunk/test/Sema/array-constraint.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/array-constraint.c?rev=44816&r1=44815&r2=44816&view=diff

==============================================================================
--- cfe/trunk/test/Sema/array-constraint.c (original)
+++ cfe/trunk/test/Sema/array-constraint.c Mon Dec 10 16:44:33 2007
@@ -45,7 +45,7 @@
 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}}
 }
 
 

Modified: cfe/trunk/test/Sema/array-init.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/array-init.c?rev=44816&r1=44815&r2=44816&view=diff

==============================================================================
--- cfe/trunk/test/Sema/array-init.c (original)
+++ cfe/trunk/test/Sema/array-init.c Mon Dec 10 16:44:33 2007
@@ -137,3 +137,28 @@
   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}}
+}
+





More information about the cfe-commits mailing list