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>. llvm-svn: 140090
This commit is contained in:
parent
1ab5e56324
commit
6b9c41ea68
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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)">;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 }
|
||||
|
|
@ -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 },
|
||||
|
|
|
|||
|
|
@ -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];
|
||||
|
|
@ -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 };
|
||||
Loading…
Reference in New Issue