[cfe-commits] r126230 - in /cfe/trunk: include/clang/Basic/DiagnosticSemaKinds.td include/clang/Sema/Initialization.h lib/Sema/SemaInit.cpp test/Sema/array-init.c

Douglas Gregor dgregor at apple.com
Tue Feb 22 10:29:51 PST 2011


Author: dgregor
Date: Tue Feb 22 12:29:51 2011
New Revision: 126230

URL: http://llvm.org/viewvc/llvm-project?rev=126230&view=rev
Log:
Implement the GNU C extension which permits the initialization of an
array from a constant array compound literal. Fixes PR9261.

Modified:
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/include/clang/Sema/Initialization.h
    cfe/trunk/lib/Sema/SemaInit.cpp
    cfe/trunk/test/Sema/array-init.c

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=126230&r1=126229&r2=126230&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Tue Feb 22 12:29:51 2011
@@ -2464,6 +2464,13 @@
 def err_array_init_not_init_list : Error<
   "array initializer must be an initializer "
   "list%select{| or string literal}0">;
+def err_array_init_different_type : Error<
+  "cannot initialize array of type %0 with array of type %1">;
+def err_array_init_non_constant_array : Error<
+  "cannot initialize array of type %0 with non-constant array of type %1">;
+def ext_array_init_copy : Extension<
+  "initialization of an array of type %0 from a compound literal of type %1 is "
+  "a GNU extension">;
 def warn_deprecated_string_literal_conversion : Warning<
   "conversion from string literal to %0 is deprecated">, InGroup<DeprecatedWritableStr>;
 def err_realimag_invalid_type : Error<"invalid type %0 to %1 operator">;

Modified: cfe/trunk/include/clang/Sema/Initialization.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Initialization.h?rev=126230&r1=126229&r2=126230&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Initialization.h (original)
+++ cfe/trunk/include/clang/Sema/Initialization.h Tue Feb 22 12:29:51 2011
@@ -467,7 +467,10 @@
     CAssignment,
 
     /// \brief String initialization
-    StringInit
+    StringInit,
+
+    /// \brief Array initialization from another array (GNU C extension).
+    ArrayInit
   };
   
   /// \brief Describes the kind of a particular step in an initialization
@@ -513,7 +516,10 @@
     SK_StringInit,
     /// \brief An initialization that "converts" an Objective-C object
     /// (not a point to an object) to another Objective-C object type.
-    SK_ObjCObjectConversion
+    SK_ObjCObjectConversion,
+    /// \brief Array initialization (from an array rvalue).
+    /// This is a GNU C extension.
+    SK_ArrayInit
   };
   
   /// \brief A single step in the initialization sequence.
@@ -563,6 +569,10 @@
     /// \brief Array must be initialized with an initializer list or a 
     /// string literal.
     FK_ArrayNeedsInitListOrStringLiteral,
+    /// \brief Array type mismatch.
+    FK_ArrayTypeMismatch,
+    /// \brief Non-constant array initializer
+    FK_NonConstantArrayInit,
     /// \brief Cannot resolve the address of an overloaded function.
     FK_AddressOfOverloadFailed,
     /// \brief Overloading due to reference initialization failed.
@@ -775,6 +785,9 @@
   /// always a no-op.
   void AddObjCObjectConversionStep(QualType T);
 
+  /// \brief Add an array initialization step.
+  void AddArrayInitStep(QualType T);
+
   /// \brief Note that this initialization sequence failed.
   void SetFailed(FailureKind Failure) {
     SequenceKind = FailedSequence;

Modified: cfe/trunk/lib/Sema/SemaInit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.cpp?rev=126230&r1=126229&r2=126230&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaInit.cpp (original)
+++ cfe/trunk/lib/Sema/SemaInit.cpp Tue Feb 22 12:29:51 2011
@@ -2074,6 +2074,7 @@
   case SK_CAssignment:
   case SK_StringInit:
   case SK_ObjCObjectConversion:
+  case SK_ArrayInit:
     break;
 
   case SK_ConversionSequence:
@@ -2105,6 +2106,8 @@
   case FK_InitListBadDestinationType:
   case FK_DefaultInitOfConst:
   case FK_Incomplete:
+  case FK_ArrayTypeMismatch:
+  case FK_NonConstantArrayInit:
     return false;
 
   case FK_ReferenceInitOverloadFailed:
@@ -2247,6 +2250,13 @@
   Steps.push_back(S);
 }
 
+void InitializationSequence::AddArrayInitStep(QualType T) {
+  Step S;
+  S.Kind = SK_ArrayInit;
+  S.Type = T;
+  Steps.push_back(S);
+}
+
 void InitializationSequence::SetOverloadFailure(FailureKind Failure,
                                                 OverloadingResult Result) {
   SequenceKind = FailedSequence;
@@ -3069,6 +3079,25 @@
   }
 }
 
+/// \brief Determine whether we have compatible array types for the
+/// purposes of GNU by-copy array initialization.
+static bool hasCompatibleArrayTypes(ASTContext &Context,
+                                    const ArrayType *Dest, 
+                                    const ArrayType *Source) {
+  // If the source and destination array types are equivalent, we're
+  // done.
+  if (Context.hasSameType(QualType(Dest, 0), QualType(Source, 0)))
+    return true;
+
+  // Make sure that the element types are the same.
+  if (!Context.hasSameType(Dest->getElementType(), Source->getElementType()))
+    return false;
+
+  // The only mismatch we allow is when the destination is an
+  // incomplete array type and the source is a constant array type.
+  return Source->isConstantArrayType() && Dest->isIncompleteArrayType();
+}
+
 InitializationSequence::InitializationSequence(Sema &S,
                                                const InitializedEntity &Entity,
                                                const InitializationKind &Kind,
@@ -3142,13 +3171,29 @@
   //       initializer is a string literal, see 8.5.2.
   //     - Otherwise, if the destination type is an array, the program is
   //       ill-formed.
-  if (const ArrayType *arrayType = Context.getAsArrayType(DestType)) {
-    if (Initializer && IsStringInit(Initializer, arrayType, Context)) {
+  if (const ArrayType *DestAT = Context.getAsArrayType(DestType)) {
+    if (Initializer && IsStringInit(Initializer, DestAT, Context)) {
       TryStringLiteralInitialization(S, Entity, Kind, Initializer, *this);
       return;
     }
 
-    if (arrayType->getElementType()->isAnyCharacterType())
+    // Note: as an GNU C extension, we allow initialization of an
+    // array from a compound literal that creates an array of the same
+    // type, so long as the initializer has no side effects.
+    if (!S.getLangOptions().CPlusPlus && Initializer &&
+        isa<CompoundLiteralExpr>(Initializer->IgnoreParens()) &&
+        Initializer->getType()->isArrayType()) {
+      const ArrayType *SourceAT
+        = Context.getAsArrayType(Initializer->getType());
+      if (!hasCompatibleArrayTypes(S.Context, DestAT, SourceAT))
+        SetFailed(FK_ArrayTypeMismatch);
+      else if (Initializer->HasSideEffects(S.Context))
+        SetFailed(FK_NonConstantArrayInit);
+      else {
+        setSequenceKind(ArrayInit);
+        AddArrayInitStep(DestType);
+      }
+    } else if (DestAT->getElementType()->isAnyCharacterType())
       SetFailed(FK_ArrayNeedsInitListOrStringLiteral);
     else
       SetFailed(FK_ArrayNeedsInitList);
@@ -3631,7 +3676,8 @@
   case SK_ListInitialization:
   case SK_CAssignment:
   case SK_StringInit:
-  case SK_ObjCObjectConversion: {
+  case SK_ObjCObjectConversion:
+  case SK_ArrayInit: {
     assert(Args.size() == 1);
     Expr *CurInitExpr = Args.get()[0];
     if (!CurInitExpr) return ExprError();
@@ -4056,6 +4102,30 @@
       CurInit.release();
       CurInit = S.Owned(CurInitExpr);
       break;
+
+    case SK_ArrayInit:
+      // Okay: we checked everything before creating this step. Note that
+      // this is a GNU extension.
+      S.Diag(Kind.getLocation(), diag::ext_array_init_copy)
+        << Step->Type << CurInitExpr->getType()
+        << CurInitExpr->getSourceRange();
+
+      // If the destination type is an incomplete array type, update the
+      // type accordingly.
+      if (ResultType) {
+        if (const IncompleteArrayType *IncompleteDest
+                           = S.Context.getAsIncompleteArrayType(Step->Type)) {
+          if (const ConstantArrayType *ConstantSource
+                 = S.Context.getAsConstantArrayType(CurInitExpr->getType())) {
+            *ResultType = S.Context.getConstantArrayType(
+                                             IncompleteDest->getElementType(),
+                                             ConstantSource->getSize(),
+                                             ArrayType::Normal, 0);
+          }
+        }
+      }
+
+      break;
     }
   }
 
@@ -4097,6 +4167,17 @@
       << (Failure == FK_ArrayNeedsInitListOrStringLiteral);
     break;
 
+  case FK_ArrayTypeMismatch:
+  case FK_NonConstantArrayInit:
+    S.Diag(Kind.getLocation(), 
+           (Failure == FK_ArrayTypeMismatch
+              ? diag::err_array_init_different_type
+              : diag::err_array_init_non_constant_array))
+      << DestType.getNonReferenceType()
+      << Args[0]->getType()
+      << Args[0]->getSourceRange();
+    break;
+
   case FK_AddressOfOverloadFailed: {
     DeclAccessPair Found;
     S.ResolveAddressOfOverloadedFunction(Args[0],
@@ -4354,6 +4435,14 @@
       OS << "array requires initializer list or string literal";
       break;
 
+    case FK_ArrayTypeMismatch:
+      OS << "array type mismatch";
+      break;
+
+    case FK_NonConstantArrayInit:
+      OS << "non-constant array initializer";
+      break;
+
     case FK_AddressOfOverloadFailed:
       OS << "address of overloaded function failed";
       break;
@@ -4457,6 +4546,10 @@
   case StringInit:
     OS << "String initialization: ";
     break;
+
+  case ArrayInit:
+    OS << "Array initialization: ";
+    break;
   }
 
   for (step_iterator S = step_begin(), SEnd = step_end(); S != SEnd; ++S) {
@@ -4536,6 +4629,10 @@
     case SK_ObjCObjectConversion:
       OS << "Objective-C object conversion";
       break;
+
+    case SK_ArrayInit:
+      OS << "array initialization";
+      break;
     }
   }
 }

Modified: cfe/trunk/test/Sema/array-init.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/array-init.c?rev=126230&r1=126229&r2=126230&view=diff
==============================================================================
--- cfe/trunk/test/Sema/array-init.c (original)
+++ cfe/trunk/test/Sema/array-init.c Tue Feb 22 12:29:51 2011
@@ -264,3 +264,17 @@
 }
 
 char badchararray[1] = { badchararray[0], "asdf" }; // expected-warning {{excess elements in array initializer}} expected-error {{initializer element is not a compile-time constant}}
+
+// Test the GNU extension for initializing an array from an array
+// compound literal. PR9261.
+typedef int int5[5];
+int a1[5] = (int[]){1, 2, 3, 4, 5}; // expected-warning{{initialization of an array of type 'int [5]' from a compound literal of type 'int [5]' is a GNU extension}}
+int a2[5] = (int[5]){1, 2, 3, 4, 5}; // expected-warning{{initialization of an array of type 'int [5]' from a compound literal of type 'int [5]' is a GNU extension}}
+int a3[] = ((int[]){1, 2, 3, 4, 5}); // expected-warning{{initialization of an array of type 'int []' from a compound literal of type 'int [5]' is a GNU extension}}
+int a4[] = (int[5]){1, 2, 3, 4, 5}; // expected-warning{{initialization of an array of type 'int []' from a compound literal of type 'int [5]' is a GNU extension}}
+int a5[] = (int5){1, 2, 3, 4, 5}; // expected-warning{{initialization of an array of type 'int []' from a compound literal of type 'int5' (aka 'int [5]') is a GNU extension}}
+
+int a6[5] = (int[]){1, 2, 3}; // expected-error{{cannot initialize array of type 'int [5]' with array of type 'int [3]'}}
+
+int nonconst_value();
+int a7[5] = (int[5]){ 1, 2, 3, 4, nonconst_value() }; // expected-error{{initializer element is not a compile-time constant}}





More information about the cfe-commits mailing list