[cfe-commits] r140090 - in /cfe/trunk: docs/LanguageExtensions.html include/clang/Basic/DiagnosticSemaKinds.td include/clang/Sema/Initialization.h lib/CodeGen/CGExprComplex.cpp lib/CodeGen/CGExprConstant.cpp lib/Sema/SemaInit.cpp test/CodeGen/complex-init-list.c test/Sema/array-init.c test/Sema/complex-init-list.c test/SemaCXX/complex-init-list.cpp

Eli Friedman eli.friedman at gmail.com
Mon Sep 19 16:17:44 PDT 2011


Author: efriedma
Date: Mon Sep 19 18:17:44 2011
New Revision: 140090

URL: http://llvm.org/viewvc/llvm-project?rev=140090&view=rev
Log:
Add list initialization for complex numbers in C.  Essentially, this allows "_Complex float x = {1.0f, 2.0f};".  See changes to docs/LanguageExtensions.html for a longer description.

<rdar://problem/9397672>.


Added:
    cfe/trunk/test/CodeGen/complex-init-list.c
    cfe/trunk/test/Sema/complex-init-list.c
    cfe/trunk/test/SemaCXX/complex-init-list.cpp
Modified:
    cfe/trunk/docs/LanguageExtensions.html
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/include/clang/Sema/Initialization.h
    cfe/trunk/lib/CodeGen/CGExprComplex.cpp
    cfe/trunk/lib/CodeGen/CGExprConstant.cpp
    cfe/trunk/lib/Sema/SemaInit.cpp
    cfe/trunk/test/Sema/array-init.c

Modified: cfe/trunk/docs/LanguageExtensions.html
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/docs/LanguageExtensions.html?rev=140090&r1=140089&r2=140090&view=diff
==============================================================================
--- cfe/trunk/docs/LanguageExtensions.html (original)
+++ cfe/trunk/docs/LanguageExtensions.html Mon Sep 19 18:17:44 2011
@@ -4,7 +4,7 @@
 <html>
 <head>
   <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
-  <title>Clang LanguageExtensions</title>
+  <title>Clang Language Extensions</title>
   <link type="text/css" rel="stylesheet" href="../menu.css">
   <link type="text/css" rel="stylesheet" href="../content.css">
   <style type="text/css">
@@ -85,6 +85,7 @@
   </ul>
 </li>
 <li><a href="#overloading-in-c">Function Overloading in C</a></li>
+<li><a href="#complex-list-init">Initializer lists for complex numbers in C</a></li>
 <li><a href="#builtins">Builtin Functions</a>
   <ul>
   <li><a href="#__builtin_shufflevector">__builtin_shufflevector</a></li>
@@ -895,6 +896,41 @@
 
 <p>Query for this feature with __has_extension(attribute_overloadable).</p>
 
+<!-- ======================================================================= -->
+<h2 id="complex-list-init">Initializer lists for complex numbers in C</h2>
+<!-- ======================================================================= -->
+
+<p>clang supports an extension which allows the following in C:</p>
+
+<blockquote>
+<pre>
+#include <math.h>
+#include <complex.h>
+complex float x = { 1.0f, INFINITY }; // Init to (1, Inf)
+</pre>
+</blockquote>
+
+<p>This construct is useful because there is no way to separately
+initialize the real and imaginary parts of a complex variable in
+standard C, given that clang does not support <code>_Imaginary</code>.
+(clang also supports the <code>__real__</code> and <code>__imag__</code>
+extensions from gcc, which help in some cases, but are not usable in
+static initializers.)
+
+<p>Note that this extension does not allow eliding the braces; the
+meaning of the following two lines is different:</p>
+
+<blockquote>
+<pre>
+complex float x[] = { { 1.0f, 1.0f } }; // [0] = (1, 1)
+complex float x[] = { 1.0f, 1.0f }; // [0] = (1, 0), [1] = (1, 0)
+</pre>
+</blockquote>
+
+<p>This extension also works in C++ mode, as far as that goes, but does not
+    apply to the C++ <code>std::complex</code>.  (In C++11, list
+    initialization allows the same syntax to be used with
+    <code>std::complex</code> with the same meaning.)
 
 <!-- ======================================================================= -->
 <h2 id="builtins">Builtin Functions</h2>

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=140090&r1=140089&r2=140090&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Mon Sep 19 18:17:44 2011
@@ -2617,6 +2617,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)">;

Modified: cfe/trunk/include/clang/Sema/Initialization.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Initialization.h?rev=140090&r1=140089&r2=140090&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Initialization.h (original)
+++ cfe/trunk/include/clang/Sema/Initialization.h Mon Sep 19 18:17:44 2011
@@ -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;
   }
 };

Modified: cfe/trunk/lib/CodeGen/CGExprComplex.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprComplex.cpp?rev=140090&r1=140089&r2=140090&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExprComplex.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExprComplex.cpp Mon Sep 19 18:17:44 2011
@@ -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);

Modified: cfe/trunk/lib/CodeGen/CGExprConstant.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprConstant.cpp?rev=140090&r1=140089&r2=140090&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExprConstant.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExprConstant.cpp Mon Sep 19 18:17:44 2011
@@ -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) {

Modified: cfe/trunk/lib/Sema/SemaInit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.cpp?rev=140090&r1=140089&r2=140090&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaInit.cpp (original)
+++ cfe/trunk/lib/Sema/SemaInit.cpp Mon Sep 19 18:17:44 2011
@@ -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 {
+  } else if (const VectorType *VT = Parent.getType()->getAs<VectorType>()) {
     Kind = EK_VectorElement;
-    Type = Parent.getType()->getAs<VectorType>()->getElementType();
+    Type = VT->getElementType();
+  } else {
+    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;

Added: cfe/trunk/test/CodeGen/complex-init-list.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/complex-init-list.c?rev=140090&view=auto
==============================================================================
--- cfe/trunk/test/CodeGen/complex-init-list.c (added)
+++ cfe/trunk/test/CodeGen/complex-init-list.c Mon Sep 19 18:17:44 2011
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -emit-llvm %s -o - -triple=x86_64-apple-darwin10 | FileCheck %s
+
+// This file tests the clang extension which allows initializing the components
+// of a complex number individually using an initialization list.  (There is a
+// extensive description and test in test/Sema/complex-init-list.c.)
+
+_Complex float x = { 1.0f, 1.0f/0.0f };
+// CHECK: @x = global { float, float } { float 1.000000e+00, float 0x7FF0000000000000 }, align 4
+
+_Complex float f(float x, float y) { _Complex float z = { x, y }; return z; }
+// CHECK: define <2 x float> @f
+// CHECK: alloca { float, float }
\ No newline at end of file

Modified: cfe/trunk/test/Sema/array-init.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/array-init.c?rev=140090&r1=140089&r2=140090&view=diff
==============================================================================
--- cfe/trunk/test/Sema/array-init.c (original)
+++ cfe/trunk/test/Sema/array-init.c Mon Sep 19 18:17:44 2011
@@ -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 },

Added: cfe/trunk/test/Sema/complex-init-list.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/complex-init-list.c?rev=140090&view=auto
==============================================================================
--- cfe/trunk/test/Sema/complex-init-list.c (added)
+++ cfe/trunk/test/Sema/complex-init-list.c Mon Sep 19 18:17:44 2011
@@ -0,0 +1,45 @@
+// 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
+_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];

Added: cfe/trunk/test/SemaCXX/complex-init-list.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/complex-init-list.cpp?rev=140090&view=auto
==============================================================================
--- cfe/trunk/test/SemaCXX/complex-init-list.cpp (added)
+++ cfe/trunk/test/SemaCXX/complex-init-list.cpp Mon Sep 19 18:17:44 2011
@@ -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 };





More information about the cfe-commits mailing list