[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