diff options
author | Eli Friedman <eli.friedman@gmail.com> | 2011-09-19 23:17:44 +0000 |
---|---|---|
committer | Eli Friedman <eli.friedman@gmail.com> | 2011-09-19 23:17:44 +0000 |
commit | 0c706c29f20b6fa36759fa41333b9c3ec0bd2969 (patch) | |
tree | cff749b4d8a9d6e5b4fbae39c4f4e710307366c0 | |
parent | 40ccaccd21a4377cd76d6adda2b192dcf9514ef6 (diff) |
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>.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@140090 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | docs/LanguageExtensions.html | 38 | ||||
-rw-r--r-- | include/clang/Basic/DiagnosticSemaKinds.td | 3 | ||||
-rw-r--r-- | include/clang/Sema/Initialization.h | 13 | ||||
-rw-r--r-- | lib/CodeGen/CGExprComplex.cpp | 9 | ||||
-rw-r--r-- | lib/CodeGen/CGExprConstant.cpp | 16 | ||||
-rw-r--r-- | lib/Sema/SemaInit.cpp | 72 | ||||
-rw-r--r-- | test/CodeGen/complex-init-list.c | 12 | ||||
-rw-r--r-- | test/Sema/array-init.c | 2 | ||||
-rw-r--r-- | test/Sema/complex-init-list.c | 45 | ||||
-rw-r--r-- | test/SemaCXX/complex-init-list.cpp | 14 |
10 files changed, 212 insertions, 12 deletions
diff --git a/docs/LanguageExtensions.html b/docs/LanguageExtensions.html index 685544f53f..0a0ada465e 100644 --- a/docs/LanguageExtensions.html +++ b/docs/LanguageExtensions.html @@ -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 @@ caveats to this use of name mangling:</p> <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> diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 4dca86f89b..494060f221 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -2617,6 +2617,9 @@ def warn_braces_around_scalar_init : Warning< "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)">; diff --git a/include/clang/Sema/Initialization.h b/include/clang/Sema/Initialization.h index fd677ef601..d92bdae307 100644 --- a/include/clang/Sema/Initialization.h +++ b/include/clang/Sema/Initialization.h @@ -67,7 +67,10 @@ public: 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 @@ private: /// 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 @@ public: /// \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; } }; diff --git a/lib/CodeGen/CGExprComplex.cpp b/lib/CodeGen/CGExprComplex.cpp index 5a752a1830..a92a7ad33e 100644 --- a/lib/CodeGen/CGExprComplex.cpp +++ b/lib/CodeGen/CGExprComplex.cpp @@ -738,10 +738,17 @@ ComplexPairTy ComplexExprEmitter::VisitInitListExpr(InitListExpr *E) { 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); diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp index c0b7045a52..d7dfa253ad 100644 --- a/lib/CodeGen/CGExprConstant.cpp +++ b/lib/CodeGen/CGExprConstant.cpp @@ -742,6 +742,22 @@ public: } 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) { diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index 5fa8486a7f..43477b266d 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -195,6 +195,11 @@ class InitListChecker { 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 @@ void InitListChecker::CheckExplicitInitList(const InitializedEntity &Entity, } } - 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 @@ void InitListChecker::CheckListElementTypes(const InitializedEntity &Entity, 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::CheckSubElementType(const InitializedEntity &Entity, } } +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 @@ InitializedEntity::InitializedEntity(ASTContext &Context, unsigned Index, 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 @@ DeclarationName InitializedEntity::getName() const { case EK_Delegating: case EK_ArrayElement: case EK_VectorElement: + case EK_ComplexElement: case EK_BlockElement: return DeclarationName(); } @@ -2124,6 +2177,7 @@ DeclaratorDecl *InitializedEntity::getDecl() const { case EK_Delegating: case EK_ArrayElement: case EK_VectorElement: + case EK_ComplexElement: case EK_BlockElement: return 0; } @@ -2147,6 +2201,7 @@ bool InitializedEntity::allowsNRVO() const { case EK_Delegating: case EK_ArrayElement: case EK_VectorElement: + case EK_ComplexElement: case EK_BlockElement: break; } @@ -2599,7 +2654,10 @@ static void TryListInitialization(Sema &S, // 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 @@ getAssignmentAction(const InitializedEntity &Entity) { 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 @@ static bool shouldBindAsTemporary(const InitializedEntity &Entity) { 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 @@ static bool shouldDestroyTemporary(const InitializedEntity &Entity) { 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 @@ static ExprResult CopyObject(Sema &S, case InitializedEntity::EK_Base: case InitializedEntity::EK_Delegating: case InitializedEntity::EK_VectorElement: + case InitializedEntity::EK_ComplexElement: case InitializedEntity::EK_BlockElement: Loc = CurInitExpr->getLocStart(); break; diff --git a/test/CodeGen/complex-init-list.c b/test/CodeGen/complex-init-list.c new file mode 100644 index 0000000000..819d4f9432 --- /dev/null +++ b/test/CodeGen/complex-init-list.c @@ -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 diff --git a/test/Sema/array-init.c b/test/Sema/array-init.c index 345ab6981b..bc958c3eea 100644 --- a/test/Sema/array-init.c +++ b/test/Sema/array-init.c @@ -53,7 +53,7 @@ void func() { 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 }, diff --git a/test/Sema/complex-init-list.c b/test/Sema/complex-init-list.c new file mode 100644 index 0000000000..5b5d7ce143 --- /dev/null +++ b/test/Sema/complex-init-list.c @@ -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]; diff --git a/test/SemaCXX/complex-init-list.cpp b/test/SemaCXX/complex-init-list.cpp new file mode 100644 index 0000000000..e75833a37d --- /dev/null +++ b/test/SemaCXX/complex-init-list.cpp @@ -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 }; |