[cfe-commits] [PATCH] Add extension to allow initializer list to initialize complex numbers by component

Eli Friedman eli.friedman at gmail.com
Fri Sep 16 17:48:10 PDT 2011


Patch attached.  Simple example this patch allows:

_Complex float x = { 1.0f, INFINITY }; // Init to (1, Inf)

This construct is useful in that currently with clang, there is no way
to correctly represent this construct in static initializers, and
representing it for non-static variables using __imag__ is messy.
According to Doug, gcc also will be implementing this extension, and
it seems like an obvious extension in the sense that there is no other
meaning which could reasonably be assigned to this construct.

Note that this extension does not allow eliding the braces; the
meaning of the following two lines is different:

_Complex float x[] = { { 1.0f, 1.0f } }; // [0] = (1, 1)
_Complex float x[] = { 1.0f, 1.0f }; // [0] = (1, 0), [1] = (1, 0)


Please comment if anyone sees any issues with this extension.
(Comments also welcome on the patch.)

(This is <rdar://problem/9397672>.)

-Eli
-------------- next part --------------
Index: test/Sema/array-init.c
===================================================================
--- test/Sema/array-init.c	(revision 139933)
+++ test/Sema/array-init.c	(working copy)
@@ -53,7 +53,7 @@
 
 void test() {
   int y1[3] = { 
-    { 1, 2, 3 } // expected-warning{{braces around scalar initializer}} expected-warning{{excess elements in scalar initializer}}
+    { 1, 2, 3 } // expected-warning{{excess elements in scalar initializer}}
   };
   int y3[4][3] = {  
     { 1, 3, 5 },
Index: test/Sema/complex-init-list.c
===================================================================
--- test/Sema/complex-init-list.c	(revision 0)
+++ test/Sema/complex-init-list.c	(revision 0)
@@ -0,0 +1,46 @@
+// RUN: %clang_cc1 %s -verify -fsyntax-only -pedantic
+
+// This file tests the clang extension which allows initializing the components
+// of a complex number individually using an initialization list. Basically,
+// if you have an explicit init list for a complex number that contains two
+// initializers, this extension kicks in to turn it into component-wise
+// initialization.
+//
+// This extension is useful because there isn't any way to accurately build
+// a complex number at the moment besides setting the components with
+// __real__ and __imag__, which is inconvenient and not usable for constants.
+// (Of course, there are other extensions we could implement that would
+// allow this, like some sort of __builtin_build_complex.)
+//
+// FIXME: It would be a good idea to have a warnings for implicit
+// real->complex and complex->real conversions; as-is, it's way too easy
+// to get implicit conversions when they are not intended.
+
+// Basic testcase
+// FIXME: Add pedantic warning
+_Complex float valid1 = { 1.0f, 2.0f }; // expected-warning {{specifying real and imaginary components is an extension}}
+
+
+// Struct for nesting tests
+struct teststruct { _Complex float x; };
+
+
+// Random other valid stuff
+_Complex int valid2 = { 1, 2 }; // expected-warning {{complex integer}} expected-warning {{specifying real and imaginary components is an extension}}
+struct teststruct valid3 = { { 1.0f, 2.0f} }; // expected-warning {{specifying real and imaginary components is an extension}}
+_Complex float valid4[2] = { {1.0f, 1.0f}, {1.0f, 1.0f} }; // expected-warning 2 {{specifying real and imaginary components is an extension}}
+// FIXME: We need some sort of warning for valid5
+_Complex float valid5 = {1.0f, 1.0fi}; // expected-warning {{imaginary constants}} expected-warning {{specifying real and imaginary components is an extension}}
+
+
+// Random invalid stuff
+struct teststruct invalid1 = { 1, 2 }; // expected-warning {{excess elements}}
+_Complex float invalid2 = { 1, 2, 3 }; // expected-warning {{excess elements}}
+_Complex float invalid3 = {}; // expected-error {{scalar initializer cannot be empty}} expected-warning {{GNU empty initializer}}
+
+
+// Check incomplete array sizing
+_Complex float sizetest1[] = { {1.0f, 1.0f}, {1.0f, 1.0f} }; // expected-warning 2 {{specifying real and imaginary components is an extension}}
+_Complex float sizecheck1[(sizeof(sizetest1) == sizeof(*sizetest1)*2) ? 1 : -1];
+_Complex float sizetest2[] = { 1.0f, 1.0f, {1.0f, 1.0f} };  // expected-warning {{specifying real and imaginary components is an extension}}
+_Complex float sizecheck2[(sizeof(sizetest2) == sizeof(*sizetest2)*3) ? 1 : -1];
Index: test/SemaCXX/complex-init-list.cpp
===================================================================
--- test/SemaCXX/complex-init-list.cpp	(revision 0)
+++ test/SemaCXX/complex-init-list.cpp	(revision 0)
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 %s -verify -fsyntax-only -pedantic
+
+// This file tests the clang extension which allows initializing the components
+// of a complex number individually using an initialization list. Basically,
+// if you have an explicit init list for a complex number that contains two
+// initializers, this extension kicks in to turn it into component-wise
+// initialization.
+// 
+// See also the testcase for the C version of this extension in
+// test/Sema/complex-init-list.c.
+
+// Basic testcase
+// (No pedantic warning is necessary because _Complex is not part of C++.)
+_Complex float valid1 = { 1.0f, 2.0f };
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td	(revision 139933)
+++ include/clang/Basic/DiagnosticSemaKinds.td	(working copy)
@@ -2615,6 +2615,9 @@
   "braces around scalar initializer">;
 def warn_many_braces_around_scalar_init : ExtWarn<
   "too many braces around scalar initializer">;
+def ext_complex_component_init : Extension<
+  "complex initialization specifying real and imaginary components "
+  "is an extension">, InGroup<DiagGroup<"complex-component-init">>;
 def err_empty_scalar_initializer : Error<"scalar initializer cannot be empty">;
 def err_illegal_initializer : Error<
   "illegal initializer (only variables can be initialized)">;
Index: include/clang/Sema/Initialization.h
===================================================================
--- include/clang/Sema/Initialization.h	(revision 139933)
+++ include/clang/Sema/Initialization.h	(working copy)
@@ -67,7 +67,10 @@
     EK_VectorElement,
     /// \brief The entity being initialized is a field of block descriptor for
     /// the copied-in c++ object.
-    EK_BlockElement
+    EK_BlockElement,
+    /// \brief The entity being initialized is the real or imaginary part of a
+    /// complex number.
+    EK_ComplexElement
   };
   
 private:
@@ -111,8 +114,9 @@
     /// virtual base.
     uintptr_t Base;
 
-    /// \brief When Kind == EK_ArrayElement or EK_VectorElement, the
-    /// index of the array or vector element being initialized. 
+    /// \brief When Kind == EK_ArrayElement, EK_VectorElement, or
+    /// EK_ComplexElement, the index of the array or vector element being
+    /// initialized. 
     unsigned Index;
   };
 
@@ -309,7 +313,8 @@
   /// \brief If this is already the initializer for an array or vector
   /// element, sets the element index.
   void setElementIndex(unsigned Index) {
-    assert(getKind() == EK_ArrayElement || getKind() == EK_VectorElement);
+    assert(getKind() == EK_ArrayElement || getKind() == EK_VectorElement ||
+           EK_ComplexElement);
     this->Index = Index;
   }
 };
Index: lib/Sema/SemaInit.cpp
===================================================================
--- lib/Sema/SemaInit.cpp	(revision 139933)
+++ lib/Sema/SemaInit.cpp	(working copy)
@@ -195,6 +195,11 @@
                            unsigned &Index,
                            InitListExpr *StructuredList,
                            unsigned &StructuredIndex);
+  void CheckComplexType(const InitializedEntity &Entity,
+                        InitListExpr *IList, QualType DeclType,
+                        unsigned &Index,
+                        InitListExpr *StructuredList,
+                        unsigned &StructuredIndex);
   void CheckScalarType(const InitializedEntity &Entity,
                        InitListExpr *IList, QualType DeclType,
                        unsigned &Index,
@@ -610,7 +615,7 @@
     }
   }
 
-  if (T->isScalarType() && !TopLevelObject)
+  if (T->isScalarType() && IList->getNumInits() == 1 && !TopLevelObject)
     SemaRef.Diag(IList->getLocStart(), diag::warn_braces_around_scalar_init)
       << IList->getSourceRange()
       << FixItHint::CreateRemoval(IList->getLocStart())
@@ -625,7 +630,12 @@
                                             InitListExpr *StructuredList,
                                             unsigned &StructuredIndex,
                                             bool TopLevelObject) {
-  if (DeclType->isScalarType()) {
+  if (DeclType->isAnyComplexType() && SubobjectIsDesignatorContext) {
+    // Explicitly braced initializer for complex type can be real+imaginary
+    // parts.
+    CheckComplexType(Entity, IList, DeclType, Index,
+                     StructuredList, StructuredIndex);
+  } else if (DeclType->isScalarType()) {
     CheckScalarType(Entity, IList, DeclType, Index,
                     StructuredList, StructuredIndex);
   } else if (DeclType->isVectorType()) {
@@ -797,6 +807,43 @@
   }
 }
 
+void InitListChecker::CheckComplexType(const InitializedEntity &Entity,
+                                       InitListExpr *IList, QualType DeclType,
+                                       unsigned &Index,
+                                       InitListExpr *StructuredList,
+                                       unsigned &StructuredIndex) {
+  assert(Index == 0 && "Index in explicit init list must be zero");
+
+  // As an extension, clang supports complex initializers, which initialize
+  // a complex number component-wise.  When an explicit initializer list for
+  // a complex number contains two two initializers, this extension kicks in:
+  // it exepcts the initializer list to contain two elements convertible to
+  // the element type of the complex type. The first element initializes
+  // the real part, and the second element intitializes the imaginary part.
+
+  if (IList->getNumInits() != 2)
+    return CheckScalarType(Entity, IList, DeclType, Index, StructuredList,
+                           StructuredIndex);
+
+  // This is an extension in C.  (The builtin _Complex type does not exist
+  // in the C++ standard.)
+  if (!SemaRef.getLangOptions().CPlusPlus)
+    SemaRef.Diag(IList->getLocStart(), diag::ext_complex_component_init)
+      << IList->getSourceRange();
+
+  // Initialize the complex number.
+  QualType elementType = DeclType->getAs<ComplexType>()->getElementType();
+  InitializedEntity ElementEntity =
+    InitializedEntity::InitializeElement(SemaRef.Context, 0, Entity);
+
+  for (unsigned i = 0; i < 2; ++i) {
+    ElementEntity.setElementIndex(Index);
+    CheckSubElementType(ElementEntity, IList, elementType, Index,
+                        StructuredList, StructuredIndex);
+  }
+}
+
+
 void InitListChecker::CheckScalarType(const InitializedEntity &Entity,
                                       InitListExpr *IList, QualType DeclType,
                                       unsigned &Index,
@@ -2060,9 +2107,14 @@
   if (const ArrayType *AT = Context.getAsArrayType(Parent.getType())) {
     Kind = EK_ArrayElement;
     Type = AT->getElementType();
+  } else if (const VectorType *VT = Parent.getType()->getAs<VectorType>()) {
+    Kind = EK_VectorElement;
+    Type = VT->getElementType();
   } else {
-    Kind = EK_VectorElement;
-    Type = Parent.getType()->getAs<VectorType>()->getElementType();
+    const ComplexType *CT = Parent.getType()->getAs<ComplexType>();
+    assert(CT && "Unexpected type");
+    Kind = EK_ComplexElement;
+    Type = CT->getElementType();
   }
 }
 
@@ -2099,6 +2151,7 @@
   case EK_Delegating:
   case EK_ArrayElement:
   case EK_VectorElement:
+  case EK_ComplexElement:
   case EK_BlockElement:
     return DeclarationName();
   }
@@ -2124,6 +2177,7 @@
   case EK_Delegating:
   case EK_ArrayElement:
   case EK_VectorElement:
+  case EK_ComplexElement:
   case EK_BlockElement:
     return 0;
   }
@@ -2147,6 +2201,7 @@
   case EK_Delegating:
   case EK_ArrayElement:
   case EK_VectorElement:
+  case EK_ComplexElement:
   case EK_BlockElement:
     break;
   }
@@ -2599,7 +2654,10 @@
   //   is equivalent to
   //
   //     T x = a;
-  if (DestType->isScalarType()) {
+  if (DestType->isAnyComplexType()) {
+    // We allow more than 1 init for complex types in some cases, even though
+    // they are scalar.
+  } else if (DestType->isScalarType()) {
     if (InitList->getNumInits() > 1 && S.getLangOptions().CPlusPlus) {
       Sequence.SetFailed(InitializationSequence::FK_TooManyInitsForScalar);
       return;
@@ -3812,6 +3870,7 @@
   case InitializedEntity::EK_Member:
   case InitializedEntity::EK_ArrayElement:
   case InitializedEntity::EK_VectorElement:
+  case InitializedEntity::EK_ComplexElement:
   case InitializedEntity::EK_BlockElement:
     return Sema::AA_Initializing;
   }
@@ -3831,6 +3890,7 @@
   case InitializedEntity::EK_Base:
   case InitializedEntity::EK_Delegating:
   case InitializedEntity::EK_VectorElement:
+  case InitializedEntity::EK_ComplexElement:
   case InitializedEntity::EK_Exception:
   case InitializedEntity::EK_BlockElement:
     return false;
@@ -3853,6 +3913,7 @@
     case InitializedEntity::EK_Base:
     case InitializedEntity::EK_Delegating:
     case InitializedEntity::EK_VectorElement:
+    case InitializedEntity::EK_ComplexElement:
     case InitializedEntity::EK_BlockElement:
       return false;
 
@@ -3938,6 +3999,7 @@
   case InitializedEntity::EK_Base:
   case InitializedEntity::EK_Delegating:
   case InitializedEntity::EK_VectorElement:
+  case InitializedEntity::EK_ComplexElement:
   case InitializedEntity::EK_BlockElement:
     Loc = CurInitExpr->getLocStart();
     break;
Index: lib/CodeGen/CGExprConstant.cpp
===================================================================
--- lib/CodeGen/CGExprConstant.cpp	(revision 139933)
+++ lib/CodeGen/CGExprConstant.cpp	(working copy)
@@ -742,6 +742,22 @@
   }
 
   llvm::Constant *VisitInitListExpr(InitListExpr *ILE) {
+    if (ILE->getType()->isAnyComplexType() && ILE->getNumInits() == 2) {
+      // Complex type with element initializers
+      Expr *Real = ILE->getInit(0);
+      Expr *Imag = ILE->getInit(1);
+      llvm::Constant *Complex[2];
+      Complex[0] = CGM.EmitConstantExpr(Real, Real->getType(), CGF);
+      if (!Complex[0])
+        return 0;
+      Complex[1] = CGM.EmitConstantExpr(Imag, Imag->getType(), CGF);
+      if (!Complex[1])
+        return 0;
+      llvm::StructType *STy =
+          cast<llvm::StructType>(ConvertType(ILE->getType()));
+      return llvm::ConstantStruct::get(STy, Complex);
+    }
+
     if (ILE->getType()->isScalarType()) {
       // We have a scalar in braces. Just use the first element.
       if (ILE->getNumInits() > 0) {
Index: lib/CodeGen/CGExprComplex.cpp
===================================================================
--- lib/CodeGen/CGExprComplex.cpp	(revision 139933)
+++ lib/CodeGen/CGExprComplex.cpp	(working copy)
@@ -738,10 +738,17 @@
     Ignore = TestAndClearIgnoreImag();
     (void)Ignore;
     assert (Ignore == false && "init list ignored");
-  if (E->getNumInits())
+
+  if (E->getNumInits() == 2) {
+    llvm::Value *Real = CGF.EmitScalarExpr(E->getInit(0));
+    llvm::Value *Imag = CGF.EmitScalarExpr(E->getInit(1));
+    return ComplexPairTy(Real, Imag);
+  } else if (E->getNumInits() == 1) {
     return Visit(E->getInit(0));
+  }
 
   // Empty init list intializes to null
+  assert(E->getNumInits() == 0 && "Unexpected number of inits");
   QualType Ty = E->getType()->getAs<ComplexType>()->getElementType();
   llvm::Type* LTy = CGF.ConvertType(Ty);
   llvm::Value* zeroConstant = llvm::Constant::getNullValue(LTy);


More information about the cfe-commits mailing list