[cfe-commits] r69153 - in /cfe/trunk: include/clang/AST/Expr.h include/clang/Basic/DiagnosticSemaKinds.td lib/AST/Expr.cpp lib/Sema/Sema.h lib/Sema/SemaExpr.cpp lib/Sema/SemaInit.cpp test/Sema/designated-initializers.c
Douglas Gregor
dgregor at apple.com
Tue Apr 14 23:41:24 PDT 2009
Author: dgregor
Date: Wed Apr 15 01:41:24 2009
New Revision: 69153
URL: http://llvm.org/viewvc/llvm-project?rev=69153&view=rev
Log:
Implement support for designated initializers that refer to members of
anonymous structs or unions. Fixes PR3778.
Modified:
cfe/trunk/include/clang/AST/Expr.h
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
cfe/trunk/lib/AST/Expr.cpp
cfe/trunk/lib/Sema/Sema.h
cfe/trunk/lib/Sema/SemaExpr.cpp
cfe/trunk/lib/Sema/SemaInit.cpp
cfe/trunk/test/Sema/designated-initializers.c
Modified: cfe/trunk/include/clang/AST/Expr.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Expr.h?rev=69153&r1=69152&r2=69153&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Expr.h (original)
+++ cfe/trunk/include/clang/AST/Expr.h Wed Apr 15 01:41:24 2009
@@ -1963,6 +1963,11 @@
/// designators, one array designator for @c [2] followed by one field
/// designator for @c .y. The initalization expression will be 1.0.
class DesignatedInitExpr : public Expr {
+public:
+ /// \brief Forward declaration of the Designator class.
+ class Designator;
+
+private:
/// The location of the '=' or ':' prior to the actual initializer
/// expression.
SourceLocation EqualOrColonLoc;
@@ -1974,17 +1979,20 @@
/// The number of designators in this initializer expression.
unsigned NumDesignators : 15;
+ /// \brief The designators in this designated initialization
+ /// expression.
+ Designator *Designators;
+
/// The number of subexpressions of this initializer expression,
/// which contains both the initializer and any additional
/// expressions used by array and array-range designators.
unsigned NumSubExprs : 16;
+
DesignatedInitExpr(QualType Ty, unsigned NumDesignators,
+ const Designator *Designators,
SourceLocation EqualOrColonLoc, bool GNUSyntax,
- unsigned NumSubExprs)
- : Expr(DesignatedInitExprClass, Ty),
- EqualOrColonLoc(EqualOrColonLoc), GNUSyntax(GNUSyntax),
- NumDesignators(NumDesignators), NumSubExprs(NumSubExprs) { }
+ unsigned NumSubExprs);
public:
/// A field designator, e.g., ".x".
@@ -2041,6 +2049,8 @@
friend class DesignatedInitExpr;
public:
+ Designator() {}
+
/// @brief Initializes a field designator.
Designator(const IdentifierInfo *FieldName, SourceLocation DotLoc,
SourceLocation FieldLoc)
@@ -2136,8 +2146,10 @@
// Iterator access to the designators.
typedef Designator* designators_iterator;
- designators_iterator designators_begin();
- designators_iterator designators_end();
+ designators_iterator designators_begin() { return Designators; }
+ designators_iterator designators_end() {
+ return Designators + NumDesignators;
+ }
Designator *getDesignator(unsigned Idx) { return &designators_begin()[Idx]; }
@@ -2162,8 +2174,15 @@
*child_begin() = init;
}
+ /// \brief Replaces the designator at index @p Idx with the series
+ /// of designators in [First, Last).
+ void ExpandDesignator(unsigned Idx, const Designator *First,
+ const Designator *Last);
+
virtual SourceRange getSourceRange() const;
+ virtual void Destroy(ASTContext &C);
+
static bool classof(const Stmt *T) {
return T->getStmtClass() == DesignatedInitExprClass;
}
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=69153&r1=69152&r2=69153&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Wed Apr 15 01:41:24 2009
@@ -49,9 +49,6 @@
def err_field_designator_nonfield : Error<
"field designator %0 does not refer to a non-static data member">;
def note_field_designator_found : Note<"field designator refers here">;
-def err_field_designator_anon_class : Error<
- "field designator %0 refers to a member of an anonymous "
- "%select{struct|class|union}1">;
def err_designator_for_scalar_init : Error<
"designator in initializer for scalar type %0">;
def warn_subobject_initializer_overrides : Warning<
Modified: cfe/trunk/lib/AST/Expr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Expr.cpp?rev=69153&r1=69152&r2=69153&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Expr.cpp (original)
+++ cfe/trunk/lib/AST/Expr.cpp Wed Apr 15 01:41:24 2009
@@ -20,6 +20,7 @@
#include "clang/AST/RecordLayout.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/Basic/TargetInfo.h"
+#include <algorithm>
using namespace clang;
//===----------------------------------------------------------------------===//
@@ -1499,6 +1500,19 @@
return getField()->getIdentifier();
}
+DesignatedInitExpr::DesignatedInitExpr(QualType Ty, unsigned NumDesignators,
+ const Designator *Designators,
+ SourceLocation EqualOrColonLoc,
+ bool GNUSyntax,
+ unsigned NumSubExprs)
+ : Expr(DesignatedInitExprClass, Ty),
+ EqualOrColonLoc(EqualOrColonLoc), GNUSyntax(GNUSyntax),
+ NumDesignators(NumDesignators), NumSubExprs(NumSubExprs) {
+ this->Designators = new Designator[NumDesignators];
+ for (unsigned I = 0; I != NumDesignators; ++I)
+ this->Designators[I] = Designators[I];
+}
+
DesignatedInitExpr *
DesignatedInitExpr::Create(ASTContext &C, Designator *Designators,
unsigned NumDesignators,
@@ -1506,10 +1520,9 @@
SourceLocation ColonOrEqualLoc,
bool UsesColonSyntax, Expr *Init) {
void *Mem = C.Allocate(sizeof(DesignatedInitExpr) +
- sizeof(Designator) * NumDesignators +
sizeof(Stmt *) * (NumIndexExprs + 1), 8);
DesignatedInitExpr *DIE
- = new (Mem) DesignatedInitExpr(C.VoidTy, NumDesignators,
+ = new (Mem) DesignatedInitExpr(C.VoidTy, NumDesignators, Designators,
ColonOrEqualLoc, UsesColonSyntax,
NumIndexExprs + 1);
@@ -1517,7 +1530,6 @@
unsigned ExpectedNumSubExprs = 0;
designators_iterator Desig = DIE->designators_begin();
for (unsigned Idx = 0; Idx < NumDesignators; ++Idx, ++Desig) {
- new (static_cast<void*>(Desig)) Designator(Designators[Idx]);
if (Designators[Idx].isArrayDesignator())
++ExpectedNumSubExprs;
else if (Designators[Idx].isArrayRangeDesignator())
@@ -1549,22 +1561,10 @@
return SourceRange(StartLoc, getInit()->getSourceRange().getEnd());
}
-DesignatedInitExpr::designators_iterator
-DesignatedInitExpr::designators_begin() {
- char* Ptr = static_cast<char*>(static_cast<void *>(this));
- Ptr += sizeof(DesignatedInitExpr);
- return static_cast<Designator*>(static_cast<void*>(Ptr));
-}
-
-DesignatedInitExpr::designators_iterator DesignatedInitExpr::designators_end() {
- return designators_begin() + NumDesignators;
-}
-
Expr *DesignatedInitExpr::getArrayIndex(const Designator& D) {
assert(D.Kind == Designator::ArrayDesignator && "Requires array designator");
char* Ptr = static_cast<char*>(static_cast<void *>(this));
Ptr += sizeof(DesignatedInitExpr);
- Ptr += sizeof(Designator) * NumDesignators;
Stmt **SubExprs = reinterpret_cast<Stmt**>(reinterpret_cast<void**>(Ptr));
return cast<Expr>(*(SubExprs + D.ArrayOrRange.Index + 1));
}
@@ -1574,7 +1574,6 @@
"Requires array range designator");
char* Ptr = static_cast<char*>(static_cast<void *>(this));
Ptr += sizeof(DesignatedInitExpr);
- Ptr += sizeof(Designator) * NumDesignators;
Stmt **SubExprs = reinterpret_cast<Stmt**>(reinterpret_cast<void**>(Ptr));
return cast<Expr>(*(SubExprs + D.ArrayOrRange.Index + 1));
}
@@ -1584,11 +1583,43 @@
"Requires array range designator");
char* Ptr = static_cast<char*>(static_cast<void *>(this));
Ptr += sizeof(DesignatedInitExpr);
- Ptr += sizeof(Designator) * NumDesignators;
Stmt **SubExprs = reinterpret_cast<Stmt**>(reinterpret_cast<void**>(Ptr));
return cast<Expr>(*(SubExprs + D.ArrayOrRange.Index + 2));
}
+/// \brief Replaces the designator at index @p Idx with the series
+/// of designators in [First, Last).
+void DesignatedInitExpr::ExpandDesignator(unsigned Idx,
+ const Designator *First,
+ const Designator *Last) {
+ unsigned NumNewDesignators = Last - First;
+ if (NumNewDesignators == 0) {
+ std::copy_backward(Designators + Idx + 1,
+ Designators + NumDesignators,
+ Designators + Idx);
+ --NumNewDesignators;
+ return;
+ } else if (NumNewDesignators == 1) {
+ Designators[Idx] = *First;
+ return;
+ }
+
+ Designator *NewDesignators
+ = new Designator[NumDesignators - 1 + NumNewDesignators];
+ std::copy(Designators, Designators + Idx, NewDesignators);
+ std::copy(First, Last, NewDesignators + Idx);
+ std::copy(Designators + Idx + 1, Designators + NumDesignators,
+ NewDesignators + Idx + NumNewDesignators);
+ delete [] Designators;
+ Designators = NewDesignators;
+ NumDesignators = NumDesignators - 1 + NumNewDesignators;
+}
+
+void DesignatedInitExpr::Destroy(ASTContext &C) {
+ delete [] Designators;
+ Expr::Destroy(C);
+}
+
//===----------------------------------------------------------------------===//
// ExprIterator.
//===----------------------------------------------------------------------===//
@@ -1774,7 +1805,6 @@
Stmt::child_iterator DesignatedInitExpr::child_begin() {
char* Ptr = static_cast<char*>(static_cast<void *>(this));
Ptr += sizeof(DesignatedInitExpr);
- Ptr += sizeof(Designator) * NumDesignators;
return reinterpret_cast<Stmt**>(reinterpret_cast<void**>(Ptr));
}
Stmt::child_iterator DesignatedInitExpr::child_end() {
Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=69153&r1=69152&r2=69153&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Wed Apr 15 01:41:24 2009
@@ -1226,6 +1226,8 @@
DeclRefExpr *BuildDeclRefExpr(NamedDecl *D, QualType Ty, SourceLocation Loc,
bool TypeDependent, bool ValueDependent,
const CXXScopeSpec *SS = 0);
+ VarDecl *BuildAnonymousStructUnionMemberPath(FieldDecl *Field,
+ llvm::SmallVectorImpl<FieldDecl *> &Path);
OwningExprResult
BuildAnonymousStructUnionMemberReference(SourceLocation Loc,
FieldDecl *Field,
Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=69153&r1=69152&r2=69153&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Wed Apr 15 01:41:24 2009
@@ -486,29 +486,33 @@
return 0;
}
-Sema::OwningExprResult
-Sema::BuildAnonymousStructUnionMemberReference(SourceLocation Loc,
- FieldDecl *Field,
- Expr *BaseObjectExpr,
- SourceLocation OpLoc) {
+/// \brief Given a field that represents a member of an anonymous
+/// struct/union, build the path from that field's context to the
+/// actual member.
+///
+/// Construct the sequence of field member references we'll have to
+/// perform to get to the field in the anonymous union/struct. The
+/// list of members is built from the field outward, so traverse it
+/// backwards to go from an object in the current context to the field
+/// we found.
+///
+/// \returns The variable from which the field access should begin,
+/// for an anonymous struct/union that is not a member of another
+/// class. Otherwise, returns NULL.
+VarDecl *Sema::BuildAnonymousStructUnionMemberPath(FieldDecl *Field,
+ llvm::SmallVectorImpl<FieldDecl *> &Path) {
assert(Field->getDeclContext()->isRecord() &&
cast<RecordDecl>(Field->getDeclContext())->isAnonymousStructOrUnion()
&& "Field must be stored inside an anonymous struct or union");
- // Construct the sequence of field member references
- // we'll have to perform to get to the field in the anonymous
- // union/struct. The list of members is built from the field
- // outward, so traverse it backwards to go from an object in
- // the current context to the field we found.
- llvm::SmallVector<FieldDecl *, 4> AnonFields;
- AnonFields.push_back(Field);
+ Path.push_back(Field);
VarDecl *BaseObject = 0;
DeclContext *Ctx = Field->getDeclContext();
do {
RecordDecl *Record = cast<RecordDecl>(Ctx);
Decl *AnonObject = getObjectForAnonymousRecordDecl(Context, Record);
if (FieldDecl *AnonField = dyn_cast<FieldDecl>(AnonObject))
- AnonFields.push_back(AnonField);
+ Path.push_back(AnonField);
else {
BaseObject = cast<VarDecl>(AnonObject);
break;
@@ -516,7 +520,19 @@
Ctx = Ctx->getParent();
} while (Ctx->isRecord() &&
cast<RecordDecl>(Ctx)->isAnonymousStructOrUnion());
-
+
+ return BaseObject;
+}
+
+Sema::OwningExprResult
+Sema::BuildAnonymousStructUnionMemberReference(SourceLocation Loc,
+ FieldDecl *Field,
+ Expr *BaseObjectExpr,
+ SourceLocation OpLoc) {
+ llvm::SmallVector<FieldDecl *, 4> AnonFields;
+ VarDecl *BaseObject = BuildAnonymousStructUnionMemberPath(Field,
+ AnonFields);
+
// Build the expression that refers to the base object, from
// which we will build a sequence of member references to each
// of the anonymous union objects and, eventually, the field we
Modified: cfe/trunk/lib/Sema/SemaInit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.cpp?rev=69153&r1=69152&r2=69153&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaInit.cpp (original)
+++ cfe/trunk/lib/Sema/SemaInit.cpp Wed Apr 15 01:41:24 2009
@@ -1031,6 +1031,64 @@
StructuredIndex);
}
+/// \brief Expand a field designator that refers to a member of an
+/// anonymous struct or union into a series of field designators that
+/// refers to the field within the appropriate subobject.
+///
+/// Field/FieldIndex will be updated to point to the (new)
+/// currently-designated field.
+static void ExpandAnonymousFieldDesignator(Sema &SemaRef,
+ DesignatedInitExpr *DIE,
+ unsigned DesigIdx,
+ FieldDecl *Field,
+ RecordDecl::field_iterator &FieldIter,
+ unsigned &FieldIndex) {
+ typedef DesignatedInitExpr::Designator Designator;
+
+ // Build the path from the current object to the member of the
+ // anonymous struct/union (backwards).
+ llvm::SmallVector<FieldDecl *, 4> Path;
+ SemaRef.BuildAnonymousStructUnionMemberPath(Field, Path);
+
+ // Build the replacement designators.
+ llvm::SmallVector<Designator, 4> Replacements;
+ for (llvm::SmallVector<FieldDecl *, 4>::reverse_iterator
+ FI = Path.rbegin(), FIEnd = Path.rend();
+ FI != FIEnd; ++FI) {
+ if (FI + 1 == FIEnd)
+ Replacements.push_back(Designator((IdentifierInfo *)0,
+ DIE->getDesignator(DesigIdx)->getDotLoc(),
+ DIE->getDesignator(DesigIdx)->getFieldLoc()));
+ else
+ Replacements.push_back(Designator((IdentifierInfo *)0, SourceLocation(),
+ SourceLocation()));
+ Replacements.back().setField(*FI);
+ }
+
+ // Expand the current designator into the set of replacement
+ // designators, so we have a full subobject path down to where the
+ // member of the anonymous struct/union is actually stored.
+ DIE->ExpandDesignator(DesigIdx, &Replacements[0],
+ &Replacements[0] + Replacements.size());
+
+ // Update FieldIter/FieldIndex;
+ RecordDecl *Record = cast<RecordDecl>(Path.back()->getDeclContext());
+ FieldIter = Record->field_begin(SemaRef.Context);
+ FieldIndex = 0;
+ for (RecordDecl::field_iterator FEnd = Record->field_end(SemaRef.Context);
+ FieldIter != FEnd; ++FieldIter) {
+ if (FieldIter->isUnnamedBitfield())
+ continue;
+
+ if (*FieldIter == Path.back())
+ return;
+
+ ++FieldIndex;
+ }
+
+ assert(false && "Unable to find anonymous struct/union field");
+}
+
/// @brief Check the well-formedness of a C99 designated initializer.
///
/// Determines whether the designated initializer @p DIE, which
@@ -1138,6 +1196,7 @@
// Note: we perform a linear search of the fields here, despite
// the fact that we have a faster lookup method, because we always
// need to compute the field's index.
+ FieldDecl *KnownField = D->getField();
IdentifierInfo *FieldName = D->getFieldName();
unsigned FieldIndex = 0;
RecordDecl::field_iterator
@@ -1147,40 +1206,50 @@
if (Field->isUnnamedBitfield())
continue;
- if (Field->getIdentifier() == FieldName)
+ if (KnownField == *Field || Field->getIdentifier() == FieldName)
break;
++FieldIndex;
}
if (Field == FieldEnd) {
- // We did not find the field we're looking for. Produce a
- // suitable diagnostic and return a failure.
+ // There was no normal field in the struct with the designated
+ // name. Perform another lookup for this name, which may find
+ // something that we can't designate (e.g., a member function),
+ // may find nothing, or may find a member of an anonymous
+ // struct/union.
DeclContext::lookup_result Lookup
= RT->getDecl()->lookup(SemaRef.Context, FieldName);
if (Lookup.first == Lookup.second) {
// Name lookup didn't find anything.
SemaRef.Diag(D->getFieldLoc(), diag::err_field_designator_unknown)
<< FieldName << CurrentObjectType;
+ ++Index;
+ return true;
+ } else if (!KnownField && isa<FieldDecl>(*Lookup.first) &&
+ cast<RecordDecl>((*Lookup.first)->getDeclContext())
+ ->isAnonymousStructOrUnion()) {
+ // Handle an field designator that refers to a member of an
+ // anonymous struct or union.
+ ExpandAnonymousFieldDesignator(SemaRef, DIE, DesigIdx,
+ cast<FieldDecl>(*Lookup.first),
+ Field, FieldIndex);
} else {
// Name lookup found something, but it wasn't a field.
SemaRef.Diag(D->getFieldLoc(), diag::err_field_designator_nonfield)
<< FieldName;
SemaRef.Diag((*Lookup.first)->getLocation(),
diag::note_field_designator_found);
- }
++Index;
return true;
- } else if (cast<RecordDecl>((*Field)->getDeclContext())
+ }
+ } else if (!KnownField &&
+ cast<RecordDecl>((*Field)->getDeclContext())
->isAnonymousStructOrUnion()) {
- SemaRef.Diag(D->getFieldLoc(), diag::err_field_designator_anon_class)
- << FieldName
- << (cast<RecordDecl>((*Field)->getDeclContext())->isUnion()? 2 :
- (int)SemaRef.getLangOptions().CPlusPlus);
- SemaRef.Diag((*Field)->getLocation(), diag::note_field_designator_found);
- ++Index;
- return true;
+ ExpandAnonymousFieldDesignator(SemaRef, DIE, DesigIdx, *Field,
+ Field, FieldIndex);
+ D = DIE->getDesignator(DesigIdx);
}
// All of the fields of a union are located at the same place in
@@ -1284,6 +1353,10 @@
if (!FinishSubobjectInit)
return false;
+ // We've already initialized something in the union; we're done.
+ if (RT->getDecl()->isUnion())
+ return hadError;
+
// Check the remaining fields within this class/struct/union subobject.
bool prevHadError = hadError;
CheckStructUnionTypes(IList, CurrentObjectType, Field, false, Index,
Modified: cfe/trunk/test/Sema/designated-initializers.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/designated-initializers.c?rev=69153&r1=69152&r2=69153&view=diff
==============================================================================
--- cfe/trunk/test/Sema/designated-initializers.c (original)
+++ cfe/trunk/test/Sema/designated-initializers.c Wed Apr 15 01:41:24 2009
@@ -187,3 +187,37 @@
.arr2[2] = 0xffff };
const union wibble wobble2 = { .arr2 = {4, 5, 6}, 7 }; // expected-warning{{excess elements in union initializer}}
+
+// PR3778
+struct s {
+ union { int i; };
+};
+struct s si = {
+ { .i = 1 }
+};
+
+double d0;
+char c0;
+float f0;
+int i0;
+
+struct Enigma {
+ union {
+ struct {
+ struct {
+ double *double_ptr;
+ char *string;
+ };
+ float *float_ptr;
+ };
+ int *int_ptr;
+ };
+ char *string2;
+};
+
+struct Enigma enigma = {
+ .double_ptr = &d0, &c0,
+ &f0, // expected-note{{previous}}
+ &c0,
+ .float_ptr = &f0 // expected-warning{{overrides}}
+};
More information about the cfe-commits
mailing list