]> granicus.if.org Git - clang/commitdiff
Implement the GNU C extension which permits the initialization of an
authorDouglas Gregor <dgregor@apple.com>
Tue, 22 Feb 2011 18:29:51 +0000 (18:29 +0000)
committerDouglas Gregor <dgregor@apple.com>
Tue, 22 Feb 2011 18:29:51 +0000 (18:29 +0000)
array from a constant array compound literal. Fixes PR9261.

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

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

index 284698222f228c60ff828703d58e52b3074b99df..0715eba69e4b6f45bbda03820cda9bf51e48f340 100644 (file)
@@ -2464,6 +2464,13 @@ def err_typecheck_incomplete_array_needs_initializer : Error<
 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">;
index c1915659905b6faacd517dbccadd2d0613648db4..bdf0d8e7b60242301166c300dcc963ce24c2195f 100644 (file)
@@ -467,7 +467,10 @@ public:
     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 @@ public:
     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 @@ public:
     /// \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 @@ public:
   /// 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;
index de6b962aa36beb5a108f1274004479ccf819f3cb..6a1bc97de7970848cf10f2c7d6dd326f3052bf63 100644 (file)
@@ -2074,6 +2074,7 @@ void InitializationSequence::Step::Destroy() {
   case SK_CAssignment:
   case SK_StringInit:
   case SK_ObjCObjectConversion:
+  case SK_ArrayInit:
     break;
 
   case SK_ConversionSequence:
@@ -2105,6 +2106,8 @@ bool InitializationSequence::isAmbiguous() const {
   case FK_InitListBadDestinationType:
   case FK_DefaultInitOfConst:
   case FK_Incomplete:
+  case FK_ArrayTypeMismatch:
+  case FK_NonConstantArrayInit:
     return false;
 
   case FK_ReferenceInitOverloadFailed:
@@ -2247,6 +2250,13 @@ void InitializationSequence::AddObjCObjectConversionStep(QualType T) {
   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 @@ static void TryUserDefinedConversion(Sema &S,
   }
 }
 
+/// \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 @@ InitializationSequence::InitializationSequence(Sema &S,
   //       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 @@ InitializationSequence::Perform(Sema &S,
   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 @@ InitializationSequence::Perform(Sema &S,
       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 @@ bool InitializationSequence::Diagnose(Sema &S,
       << (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 @@ void InitializationSequence::dump(llvm::raw_ostream &OS) const {
       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 @@ void InitializationSequence::dump(llvm::raw_ostream &OS) const {
   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 @@ void InitializationSequence::dump(llvm::raw_ostream &OS) const {
     case SK_ObjCObjectConversion:
       OS << "Objective-C object conversion";
       break;
+
+    case SK_ArrayInit:
+      OS << "array initialization";
+      break;
     }
   }
 }
index 0ee22c0f1994891a6a5fd127a2f77b3fa232cf94..345ab6981b17d9d885e3d33b41cba9a0c4fdf789 100644 (file)
@@ -264,3 +264,17 @@ void test_matrix() {
 }
 
 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}}