On Tue, May 20, 2014 at 03:12:08PM -0700, Nico Weber wrote:
> On Tue, May 20, 2014 at 2:53 PM, Peter Collingbourne <[email protected]>wrote:
> 
> > On Tue, May 20, 2014 at 09:21:38PM +0000, Nico Weber wrote:
> > > Is there a list of extensions you want to support?
> >
> > I want to implement the unnamed substructure extension (section 3.3 here:
> > http://plan9.bell-labs.com/sys/doc/compiler.html). As far as I know, that
> > is the only other extension required for the Go standard library.
> >
> 
> Hm, that doesn't sound so bad.
> 
> Do you happen to have a complete diff for all the changes you want to make
> that you could put somewhere? It sounds like it would be relatively small.

I have unnamed substructures implemented (attached). No docs or tests yet,
though it does allow me to compile the Go standard library. (It is in fact
a relatively large diff, but most of it is boilerplate changes.)

> What are the odds of the go standard library depending on more plan9 stuff
> over time?

I don't know. But I hope it wouldn't go much beyond what GCC already implements
(namely, unnamed substructures).

> > > Could the go standard library not use plan9 extensions, if it's
> > interested
> > > in being compiled with more than 1 compiler?
> >
> > I don't know how receptive the Go folks would be to that.
> 
> 
> Have you asked?

I haven't. I should probably do that.

Thanks,
-- 
Peter
commit 206d6ba77c7a264337d493c828e685b439d3640a
Author: Peter Collingbourne <[email protected]>
Date:   Tue May 20 13:34:14 2014 -0700

    Implement a Plan 9 extension that permits unnamed substructures.
    
    This extension is similar to an already implemented Microsoft C extension, but
    it also allows implicit conversions from structures to unnamed substructutres,
    and references to unnamed substructures by typedef name.
    
    The extension is documented in section 3.3 of:
    http://plan9.bell-labs.com/sys/doc/compiler.html

diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h
index f654791..6c79d90 100644
--- a/include/clang/AST/Decl.h
+++ b/include/clang/AST/Decl.h
@@ -2149,7 +2149,8 @@ public:
 class FieldDecl : public DeclaratorDecl, public Mergeable<FieldDecl> {
   // FIXME: This can be packed into the bitfields in Decl.
   bool Mutable : 1;
-  mutable unsigned CachedFieldIndex : 31;
+  bool IsUnnamedSubstructure : 1;
+  mutable unsigned CachedFieldIndex : 30;
 
   /// \brief An InClassInitStyle value, and either a bit width expression (if
   /// the InClassInitStyle value is ICIS_NoInit), or a pointer to the in-class
@@ -2164,12 +2165,12 @@ class FieldDecl : public DeclaratorDecl, public Mergeable<FieldDecl> {
   llvm::PointerIntPair<Expr *, 2, unsigned> InitializerOrBitWidth;
 protected:
   FieldDecl(Kind DK, DeclContext *DC, SourceLocation StartLoc,
-            SourceLocation IdLoc, IdentifierInfo *Id,
-            QualType T, TypeSourceInfo *TInfo, Expr *BW, bool Mutable,
-            InClassInitStyle InitStyle)
-    : DeclaratorDecl(DK, DC, IdLoc, Id, T, TInfo, StartLoc),
-      Mutable(Mutable), CachedFieldIndex(0),
-      InitializerOrBitWidth(BW, InitStyle) {
+            SourceLocation IdLoc, IdentifierInfo *Id, QualType T,
+            TypeSourceInfo *TInfo, Expr *BW, bool Mutable,
+            bool IsUnnamedSubstructure, InClassInitStyle InitStyle)
+      : DeclaratorDecl(DK, DC, IdLoc, Id, T, TInfo, StartLoc), Mutable(Mutable),
+        IsUnnamedSubstructure(IsUnnamedSubstructure), CachedFieldIndex(0),
+        InitializerOrBitWidth(BW, InitStyle) {
     assert((!BW || InitStyle == ICIS_NoInit) && "got initializer for bitfield");
   }
 
@@ -2178,6 +2179,7 @@ public:
                            SourceLocation StartLoc, SourceLocation IdLoc,
                            IdentifierInfo *Id, QualType T,
                            TypeSourceInfo *TInfo, Expr *BW, bool Mutable,
+                           bool IsUnnamedSubstructure,
                            InClassInitStyle InitStyle);
 
   static FieldDecl *CreateDeserialized(ASTContext &C, unsigned ID);
@@ -2189,6 +2191,14 @@ public:
   /// isMutable - Determines whether this field is mutable (C++ only).
   bool isMutable() const { return Mutable; }
 
+  /// \brief Returns whether this field holds an unnamed substructure (Plan 9
+  /// extension).
+  ///
+  /// This cannot be determined purely by checking whether the FieldDecl is
+  /// named because an unnamed substructure member declared with a typedef type
+  /// is represented using a named FieldDecl.
+  bool isUnnamedSubstructure() const { return IsUnnamedSubstructure; }
+
   /// isBitfield - Determines whether this field is a bitfield.
   bool isBitField() const {
     return getInClassInitStyle() == ICIS_NoInit &&
diff --git a/include/clang/AST/DeclObjC.h b/include/clang/AST/DeclObjC.h
index 4ca02d2..6de6c9e 100644
--- a/include/clang/AST/DeclObjC.h
+++ b/include/clang/AST/DeclObjC.h
@@ -1399,7 +1399,8 @@ private:
                QualType T, TypeSourceInfo *TInfo, AccessControl ac, Expr *BW,
                bool synthesized)
     : FieldDecl(ObjCIvar, DC, StartLoc, IdLoc, Id, T, TInfo, BW,
-                /*Mutable=*/false, /*HasInit=*/ICIS_NoInit),
+                /*Mutable=*/false, /*IsUnnamedSubstructure=*/false,
+                /*HasInit=*/ICIS_NoInit),
       NextIvar(nullptr), DeclAccess(ac), Synthesized(synthesized) {}
 
 public:
@@ -1455,7 +1456,8 @@ class ObjCAtDefsFieldDecl : public FieldDecl {
                       QualType T, Expr *BW)
     : FieldDecl(ObjCAtDefsField, DC, StartLoc, IdLoc, Id, T,
                 /*TInfo=*/nullptr, // FIXME: Do ObjCAtDefs have declarators ?
-                BW, /*Mutable=*/false, /*HasInit=*/ICIS_NoInit) {}
+                BW, /*Mutable=*/false, /*IsUnnamedSubstructure=*/false,
+                /*HasInit=*/ICIS_NoInit) {}
 
 public:
   static ObjCAtDefsFieldDecl *Create(ASTContext &C, DeclContext *DC,
diff --git a/include/clang/AST/OperationKinds.h b/include/clang/AST/OperationKinds.h
index aba88d6..6a4b2d1 100644
--- a/include/clang/AST/OperationKinds.h
+++ b/include/clang/AST/OperationKinds.h
@@ -298,7 +298,15 @@ enum CastKind {
   CK_ZeroToOCLEvent,
 
   // Convert a pointer to a different address space.
-  CK_AddressSpaceConversion
+  CK_AddressSpaceConversion,
+
+  /// \brief Plan 9 extension: implicit conversion of a structure to an unnamed
+  /// substructure.
+  CK_UnnamedSubstructure,
+
+  /// \brief Plan 9 extension: implicit conversion of a pointer to a structure
+  /// to a pointer to an unnamed substructure.
+  CK_UnnamedSubstructurePointer,
 };
 
 static const CastKind CK_Invalid = static_cast<CastKind>(-1);
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index f4a1a35..576308a 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -1741,8 +1741,7 @@ public:
                                     RecordDecl *Record,
                                     const PrintingPolicy &Policy);
 
-  Decl *BuildMicrosoftCAnonymousStruct(Scope *S, DeclSpec &DS,
-                                       RecordDecl *Record);
+  Decl *BuildAnonymousStruct(Scope *S, DeclSpec &DS, RecordDecl *Record);
 
   bool isAcceptableTagRedeclaration(const TagDecl *Previous,
                                     TagTypeKind NewTag, bool isDefinition,
@@ -7563,6 +7562,9 @@ public:
   void DiagnoseAssignmentEnum(QualType DstType, QualType SrcType,
                               Expr *SrcExpr);
 
+  bool PromoteToUnnamedSubstructure(QualType LHSType, QualType RHSType,
+                                    ExprResult &RHS, bool IsPointer);
+
   /// CheckAssignmentConstraints - Perform type checking for assignment,
   /// argument passing, variable initialization, and function return values.
   /// C99 6.5.16.
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index fe735dc..b4d6ab7 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -4581,6 +4581,7 @@ QualType ASTContext::getCFConstantStringType() const {
                                            FieldTypes[i], /*TInfo=*/nullptr,
                                            /*BitWidth=*/nullptr,
                                            /*Mutable=*/false,
+                                           /*IsUnnamedSubstructure=*/false,
                                            ICIS_NoInit);
       Field->setAccess(AS_public);
       CFConstantStringTypeDecl->addDecl(Field);
@@ -4630,7 +4631,8 @@ QualType ASTContext::getBlockDescriptorType() const {
     FieldDecl *Field = FieldDecl::Create(
         *this, RD, SourceLocation(), SourceLocation(),
         &Idents.get(FieldNames[i]), FieldTypes[i], /*TInfo=*/nullptr,
-        /*BitWidth=*/nullptr, /*Mutable=*/false, ICIS_NoInit);
+        /*BitWidth=*/nullptr, /*Mutable=*/false,
+        /*IsUnnamedSubstructure=*/false, ICIS_NoInit);
     Field->setAccess(AS_public);
     RD->addDecl(Field);
   }
@@ -4669,8 +4671,8 @@ QualType ASTContext::getBlockDescriptorExtendedType() const {
     FieldDecl *Field = FieldDecl::Create(
         *this, RD, SourceLocation(), SourceLocation(),
         &Idents.get(FieldNames[i]), FieldTypes[i], /*TInfo=*/nullptr,
-        /*BitWidth=*/nullptr,
-        /*Mutable=*/false, ICIS_NoInit);
+        /*BitWidth=*/nullptr, /*Mutable=*/false,
+        /*IsUnnamedSubstructure=*/false, ICIS_NoInit);
     Field->setAccess(AS_public);
     RD->addDecl(Field);
   }
@@ -5831,6 +5833,7 @@ CreateAArch64ABIBuiltinVaListDecl(const ASTContext *Context) {
                                          FieldTypes[i], /*TInfo=*/nullptr,
                                          /*BitWidth=*/nullptr,
                                          /*Mutable=*/false,
+                                         /*IsUnnamedSubstructure=*/false,
                                          ICIS_NoInit);
     Field->setAccess(AS_public);
     VaListTagDecl->addDecl(Field);
@@ -5883,6 +5886,7 @@ static TypedefDecl *CreatePowerABIBuiltinVaListDecl(const ASTContext *Context) {
                                          FieldTypes[i], /*TInfo=*/nullptr,
                                          /*BitWidth=*/nullptr,
                                          /*Mutable=*/false,
+                                         /*IsUnnamedSubstructure=*/false,
                                          ICIS_NoInit);
     Field->setAccess(AS_public);
     VaListTagDecl->addDecl(Field);
@@ -5943,6 +5947,7 @@ CreateX86_64ABIBuiltinVaListDecl(const ASTContext *Context) {
                                          FieldTypes[i], /*TInfo=*/nullptr,
                                          /*BitWidth=*/nullptr,
                                          /*Mutable=*/false,
+                                         /*IsUnnamedSubstructure=*/false,
                                          ICIS_NoInit);
     Field->setAccess(AS_public);
     VaListTagDecl->addDecl(Field);
@@ -6003,6 +6008,7 @@ CreateAAPCSABIBuiltinVaListDecl(const ASTContext *Context) {
                                        /*TInfo=*/nullptr,
                                        /*BitWidth=*/nullptr,
                                        /*Mutable=*/false,
+                                       /*IsUnnamedSubstructure=*/false,
                                        ICIS_NoInit);
   Field->setAccess(AS_public);
   VaListDecl->addDecl(Field);
@@ -6052,6 +6058,7 @@ CreateSystemZBuiltinVaListDecl(const ASTContext *Context) {
                                          FieldTypes[i], /*TInfo=*/nullptr,
                                          /*BitWidth=*/nullptr,
                                          /*Mutable=*/false,
+                                         /*IsUnnamedSubstructure=*/false,
                                          ICIS_NoInit);
     Field->setAccess(AS_public);
     VaListTagDecl->addDecl(Field);
diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp
index b180326..8f954d8 100644
--- a/lib/AST/ASTImporter.cpp
+++ b/lib/AST/ASTImporter.cpp
@@ -2893,6 +2893,7 @@ Decl *ASTNodeImporter::VisitFieldDecl(FieldDecl *D) {
                                          Importer.Import(D->getInnerLocStart()),
                                          Loc, Name.getAsIdentifierInfo(),
                                          T, TInfo, BitWidth, D->isMutable(),
+                                         D->isUnnamedSubstructure(),
                                          D->getInClassInitStyle());
   ToField->setAccess(D->getAccess());
   ToField->setLexicalDeclContext(LexicalDC);
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index fc15bde..8134737 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -3146,15 +3146,16 @@ FieldDecl *FieldDecl::Create(const ASTContext &C, DeclContext *DC,
                              SourceLocation StartLoc, SourceLocation IdLoc,
                              IdentifierInfo *Id, QualType T,
                              TypeSourceInfo *TInfo, Expr *BW, bool Mutable,
+                             bool IsUnnamedSubstructure,
                              InClassInitStyle InitStyle) {
   return new (C, DC) FieldDecl(Decl::Field, DC, StartLoc, IdLoc, Id, T, TInfo,
-                               BW, Mutable, InitStyle);
+                               BW, Mutable, IsUnnamedSubstructure, InitStyle);
 }
 
 FieldDecl *FieldDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
   return new (C, ID) FieldDecl(Field, nullptr, SourceLocation(),
                                SourceLocation(), nullptr, QualType(), nullptr,
-                               nullptr, false, ICIS_NoInit);
+                               nullptr, false, false, ICIS_NoInit);
 }
 
 bool FieldDecl::isAnonymousStructOrUnion() const {
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index aea2f43..c600a7c 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -1496,6 +1496,8 @@ bool CastExpr::CastConsistency() const {
   case CK_ARCReclaimReturnedObject:
   case CK_ARCExtendBlockObject:
   case CK_ZeroToOCLEvent:
+  case CK_UnnamedSubstructure:
+  case CK_UnnamedSubstructurePointer:
     assert(!getType()->isBooleanType() && "unheralded conversion to bool");
     goto CheckNoBasePath;
 
@@ -1632,6 +1634,10 @@ const char *CastExpr::getCastKindName() const {
     return "ZeroToOCLEvent";
   case CK_AddressSpaceConversion:
     return "AddressSpaceConversion";
+  case CK_UnnamedSubstructure:
+    return "UnnamedSubstructure";
+  case CK_UnnamedSubstructurePointer:
+    return "UnnamedSubstructurePointer";
   }
 
   llvm_unreachable("Unhandled cast kind!");
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index c1468cb..40cb7cf 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -7134,6 +7134,8 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) {
   case CK_ZeroToOCLEvent:
   case CK_NonAtomicToAtomic:
   case CK_AddressSpaceConversion:
+  case CK_UnnamedSubstructure:
+  case CK_UnnamedSubstructurePointer:
     llvm_unreachable("invalid cast kind for integral value");
 
   case CK_BitCast:
@@ -7607,6 +7609,8 @@ bool ComplexExprEvaluator::VisitCastExpr(const CastExpr *E) {
   case CK_ZeroToOCLEvent:
   case CK_NonAtomicToAtomic:
   case CK_AddressSpaceConversion:
+  case CK_UnnamedSubstructure:
+  case CK_UnnamedSubstructurePointer:
     llvm_unreachable("invalid cast kind for complex value");
 
   case CK_LValueToRValue:
diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp
index ebd160b..e5428f1 100644
--- a/lib/CodeGen/CGExpr.cpp
+++ b/lib/CodeGen/CGExpr.cpp
@@ -2801,6 +2801,7 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
   case CK_ARCExtendBlockObject:
   case CK_CopyAndAutoreleaseBlockObject:
   case CK_AddressSpaceConversion:
+  case CK_UnnamedSubstructurePointer:
     return EmitUnsupportedLValue(E, "unexpected cast lvalue");
 
   case CK_Dependent:
@@ -2827,6 +2828,7 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
   case CK_BlockPointerToObjCPointerCast:
   case CK_NoOp:
   case CK_LValueToRValue:
+  case CK_UnnamedSubstructure:
     return EmitLValue(E->getSubExpr());
 
   case CK_UncheckedDerivedToBase:
diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp
index 6c50521..ab2f060 100644
--- a/lib/CodeGen/CGExprAgg.cpp
+++ b/lib/CodeGen/CGExprAgg.cpp
@@ -662,6 +662,7 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) {
   case CK_NoOp:
   case CK_UserDefinedConversion:
   case CK_ConstructorConversion:
+  case CK_UnnamedSubstructure:
     assert(CGF.getContext().hasSameUnqualifiedType(E->getSubExpr()->getType(),
                                                    E->getType()) &&
            "Implicit cast types must be compatible");
@@ -714,6 +715,7 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) {
   case CK_BuiltinFnToFnPtr:
   case CK_ZeroToOCLEvent:
   case CK_AddressSpaceConversion:
+  case CK_UnnamedSubstructurePointer:
     llvm_unreachable("cast kind invalid for aggregate types");
   }
 }
diff --git a/lib/CodeGen/CGExprComplex.cpp b/lib/CodeGen/CGExprComplex.cpp
index 1f84c86..d797968 100644
--- a/lib/CodeGen/CGExprComplex.cpp
+++ b/lib/CodeGen/CGExprComplex.cpp
@@ -476,6 +476,8 @@ ComplexPairTy ComplexExprEmitter::EmitCast(CastExpr::CastKind CK, Expr *Op,
   case CK_BuiltinFnToFnPtr:
   case CK_ZeroToOCLEvent:
   case CK_AddressSpaceConversion:
+  case CK_UnnamedSubstructure:
+  case CK_UnnamedSubstructurePointer:
     llvm_unreachable("invalid cast kind for complex value");
 
   case CK_FloatingRealToComplex:
diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp
index 4e61592..1ef06e8 100644
--- a/lib/CodeGen/CGExprConstant.cpp
+++ b/lib/CodeGen/CGExprConstant.cpp
@@ -701,6 +701,8 @@ public:
     case CK_FloatingToBoolean:
     case CK_FloatingCast:
     case CK_ZeroToOCLEvent:
+    case CK_UnnamedSubstructure:
+    case CK_UnnamedSubstructurePointer:
       return 0;
     }
     llvm_unreachable("Invalid CastKind");
diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp
index 522a0e2..a64e181 100644
--- a/lib/CodeGen/CGExprScalar.cpp
+++ b/lib/CodeGen/CGExprScalar.cpp
@@ -1313,6 +1313,7 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
   case CK_NonAtomicToAtomic:
   case CK_NoOp:
   case CK_UserDefinedConversion:
+  case CK_UnnamedSubstructure:
     return Visit(const_cast<Expr*>(E));
 
   case CK_BaseToDerived: {
@@ -1371,6 +1372,7 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
     return CGF.Builder.CreatePointerCast(V, ConvertType(CE->getType()));
   }
   case CK_FunctionToPointerDecay:
+  case CK_UnnamedSubstructurePointer:
     return EmitLValue(E).getAddress();
 
   case CK_NullToPointer:
diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp
index 575884b..a4e0b70 100644
--- a/lib/CodeGen/CGObjCMac.cpp
+++ b/lib/CodeGen/CGObjCMac.cpp
@@ -5057,9 +5057,10 @@ ObjCCommonTypesHelper::ObjCCommonTypesHelper(CodeGen::CodeGenModule &cgm)
                                       SourceLocation(), SourceLocation(),
                                       &Ctx.Idents.get("_objc_super"));
   RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), SourceLocation(), 0,
-                                Ctx.getObjCIdType(), 0, 0, false, ICIS_NoInit));
+                                Ctx.getObjCIdType(), 0, 0, false, false,
+                                ICIS_NoInit));
   RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), SourceLocation(), 0,
-                                Ctx.getObjCClassType(), 0, 0, false,
+                                Ctx.getObjCClassType(), 0, 0, false, false,
                                 ICIS_NoInit));
   RD->completeDefinition();
 
@@ -5438,9 +5439,10 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul
                                       SourceLocation(), SourceLocation(),
                                       &Ctx.Idents.get("_message_ref_t"));
   RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), SourceLocation(), 0,
-                                Ctx.VoidPtrTy, 0, 0, false, ICIS_NoInit));
+                                Ctx.VoidPtrTy, 0, 0, false, false,
+                                ICIS_NoInit));
   RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), SourceLocation(), 0,
-                                Ctx.getObjCSelType(), 0, 0, false,
+                                Ctx.getObjCSelType(), 0, 0, false, false,
                                 ICIS_NoInit));
   RD->completeDefinition();
 
diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp
index af257c5..a3c4ad2 100644
--- a/lib/CodeGen/CodeGenModule.cpp
+++ b/lib/CodeGen/CodeGenModule.cpp
@@ -2527,6 +2527,7 @@ CodeGenModule::GetAddrOfConstantString(const StringLiteral *Literal) {
                                            FieldTypes[i], /*TInfo=*/0,
                                            /*BitWidth=*/0,
                                            /*Mutable=*/false,
+                                           /*IsUnnamedSubstructure=*/false,
                                            ICIS_NoInit);
       Field->setAccess(AS_public);
       D->addDecl(Field);
@@ -2602,6 +2603,7 @@ QualType CodeGenModule::getObjCFastEnumerationStateType() {
                                            FieldTypes[i], /*TInfo=*/0,
                                            /*BitWidth=*/0,
                                            /*Mutable=*/false,
+                                           /*IsUnnamedSubstructure=*/false,
                                            ICIS_NoInit);
       Field->setAccess(AS_public);
       D->addDecl(Field);
diff --git a/lib/Edit/RewriteObjCFoundationAPI.cpp b/lib/Edit/RewriteObjCFoundationAPI.cpp
index 666844c..bc4d5e7 100644
--- a/lib/Edit/RewriteObjCFoundationAPI.cpp
+++ b/lib/Edit/RewriteObjCFoundationAPI.cpp
@@ -1076,6 +1076,8 @@ static bool rewriteToNumericBoxedExpression(const ObjCMessageExpr *Msg,
     case CK_CopyAndAutoreleaseBlockObject:
     case CK_BuiltinFnToFnPtr:
     case CK_ZeroToOCLEvent:
+    case CK_UnnamedSubstructure:
+    case CK_UnnamedSubstructurePointer:
       return false;
     }
   }
diff --git a/lib/Rewrite/Frontend/RewriteModernObjC.cpp b/lib/Rewrite/Frontend/RewriteModernObjC.cpp
index 3cacbdd..7e3dbc6 100644
--- a/lib/Rewrite/Frontend/RewriteModernObjC.cpp
+++ b/lib/Rewrite/Frontend/RewriteModernObjC.cpp
@@ -899,6 +899,7 @@ RewriteModernObjC::getIvarAccessString(ObjCIvarDecl *D) {
                                         &Context->Idents.get(D->getNameAsString()),
                                         IvarT, nullptr,
                                         /*BitWidth=*/nullptr, /*Mutable=*/true,
+                                        /*IsUnnamedSubstructure=*/false,
                                         ICIS_NoInit);
       MemberExpr *ME = new (Context) MemberExpr(PE, true, FD, SourceLocation(),
                                                 FD->getType(), VK_LValue,
@@ -2776,7 +2777,9 @@ Stmt *RewriteModernObjC::RewriteObjCArrayLiteralExpr(ObjCArrayLiteral *Exp) {
                                     &Context->Idents.get("arr"),
                                     Context->getPointerType(Context->VoidPtrTy),
                                     nullptr, /*BitWidth=*/nullptr,
-                                    /*Mutable=*/true, ICIS_NoInit);
+                                    /*Mutable=*/true,
+                                    /*IsUnnamedSubstructure=*/false,
+                                    ICIS_NoInit);
   MemberExpr *ArrayLiteralME = 
     new (Context) MemberExpr(NSArrayCallExpr, false, ARRFD, 
                              SourceLocation(),
@@ -2913,7 +2916,9 @@ Stmt *RewriteModernObjC::RewriteObjCDictionaryLiteralExpr(ObjCDictionaryLiteral
                                        &Context->Idents.get("arr"),
                                        Context->getPointerType(Context->VoidPtrTy),
                                        nullptr, /*BitWidth=*/nullptr,
-                                       /*Mutable=*/true, ICIS_NoInit);
+                                       /*Mutable=*/true,
+                                       /*IsUnnamedSubstructure=*/false,
+                                       ICIS_NoInit);
   MemberExpr *DictLiteralValueME = 
     new (Context) MemberExpr(NSValueCallExpr, false, ARRFD, 
                              SourceLocation(),
@@ -3049,6 +3054,7 @@ QualType RewriteModernObjC::getSuperStructType() {
                                                  FieldTypes[i], nullptr,
                                                  /*BitWidth=*/nullptr,
                                                  /*Mutable=*/false,
+                                                /*IsUnnamedSubstructure=*/false,
                                                  ICIS_NoInit));
     }
 
@@ -3082,6 +3088,7 @@ QualType RewriteModernObjC::getConstantStringStructType() {
                                                     FieldTypes[i], nullptr,
                                                     /*BitWidth=*/nullptr,
                                                     /*Mutable=*/true,
+                                                /*IsUnnamedSubstructure=*/false,
                                                     ICIS_NoInit));
     }
 
@@ -3243,7 +3250,9 @@ Expr *RewriteModernObjC::SynthMsgSendStretCallExpr(FunctionDecl *MsgSendStretFla
                                     &Context->Idents.get("s"),
                                     returnType, nullptr,
                                     /*BitWidth=*/nullptr,
-                                    /*Mutable=*/true, ICIS_NoInit);
+                                    /*Mutable=*/true,
+                                    /*IsUnnamedSubstructure=*/false,
+                                    ICIS_NoInit);
   MemberExpr *ME = new (Context) MemberExpr(STCE, false, FieldD, SourceLocation(),
                                             FieldD->getType(), VK_LValue,
                                             OK_Ordinary);
@@ -3897,7 +3906,7 @@ QualType RewriteModernObjC::SynthesizeBitfieldGroupStructType(
                                   &Context->Idents.get(Ivar->getName()),
                                   Ivar->getType(),
                                   nullptr, /*Expr *BW */Ivar->getBitWidth(),
-                                  false, ICIS_NoInit));
+                                  false, false, ICIS_NoInit));
   }
   RD->completeDefinition();
   return Context->getTagDeclType(RD);
@@ -4751,6 +4760,7 @@ Stmt *RewriteModernObjC::SynthesizeBlockCall(CallExpr *Exp, const Expr *BlockExp
                                     &Context->Idents.get("FuncPtr"),
                                     Context->VoidPtrTy, nullptr,
                                     /*BitWidth=*/nullptr, /*Mutable=*/true,
+                                    /*IsUnnamedSubstructure=*/false,
                                     ICIS_NoInit);
   MemberExpr *ME = new (Context) MemberExpr(PE, true, FD, SourceLocation(),
                                             FD->getType(), VK_LValue,
@@ -4799,6 +4809,7 @@ Stmt *RewriteModernObjC::RewriteBlockDeclRefExpr(DeclRefExpr *DeclRefExp) {
                                     &Context->Idents.get("__forwarding"), 
                                     Context->VoidPtrTy, nullptr,
                                     /*BitWidth=*/nullptr, /*Mutable=*/true,
+                                    /*IsUnnamedSubstructure=*/false,
                                     ICIS_NoInit);
   MemberExpr *ME = new (Context) MemberExpr(DeclRefExp, isArrow,
                                             FD, SourceLocation(),
@@ -4810,6 +4821,7 @@ Stmt *RewriteModernObjC::RewriteBlockDeclRefExpr(DeclRefExpr *DeclRefExp) {
                          &Context->Idents.get(Name), 
                          Context->VoidPtrTy, nullptr,
                          /*BitWidth=*/nullptr, /*Mutable=*/true,
+                         /*IsUnnamedSubstructure=*/false,
                          ICIS_NoInit);
   ME = new (Context) MemberExpr(ME, true, FD, SourceLocation(),
                                 DeclRefExp->getType(), VK_LValue, OK_Ordinary);
@@ -7709,7 +7721,9 @@ Stmt *RewriteModernObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV) {
                                             &Context->Idents.get(D->getNameAsString()),
                                             IvarT, nullptr,
                                             /*BitWidth=*/nullptr,
-                                            /*Mutable=*/true, ICIS_NoInit);
+                                            /*Mutable=*/true,
+                                            /*IsUnnamedSubstructure=*/false,
+                                            ICIS_NoInit);
           MemberExpr *ME = new (Context) MemberExpr(PE, true, FD, SourceLocation(),
                                                     FD->getType(), VK_LValue,
                                                     OK_Ordinary);
@@ -7738,7 +7752,9 @@ Stmt *RewriteModernObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV) {
                                           &Context->Idents.get(D->getNameAsString()),
                                           D->getType(), nullptr,
                                           /*BitWidth=*/D->getBitWidth(),
-                                          /*Mutable=*/true, ICIS_NoInit);
+                                          /*Mutable=*/true,
+                                          /*IsUnnamedSubstructure=*/false,
+                                          ICIS_NoInit);
         MemberExpr *ME = new (Context) MemberExpr(PE, /*isArrow*/false, FD, SourceLocation(),
                                                   FD->getType(), VK_LValue,
                                                   OK_Ordinary);
diff --git a/lib/Rewrite/Frontend/RewriteObjC.cpp b/lib/Rewrite/Frontend/RewriteObjC.cpp
index beadb93..2d9ced9 100644
--- a/lib/Rewrite/Frontend/RewriteObjC.cpp
+++ b/lib/Rewrite/Frontend/RewriteObjC.cpp
@@ -2550,6 +2550,7 @@ QualType RewriteObjC::getSuperStructType() {
                                                  FieldTypes[i], nullptr,
                                                  /*BitWidth=*/nullptr,
                                                  /*Mutable=*/false,
+                                                /*IsUnnamedSubstructure=*/false,
                                                  ICIS_NoInit));
     }
 
@@ -2583,6 +2584,7 @@ QualType RewriteObjC::getConstantStringStructType() {
                                                     FieldTypes[i], nullptr,
                                                     /*BitWidth=*/nullptr,
                                                     /*Mutable=*/true,
+                                                /*IsUnnamedSubstructure=*/false,
                                                     ICIS_NoInit));
     }
 
@@ -3834,6 +3836,7 @@ Stmt *RewriteObjC::SynthesizeBlockCall(CallExpr *Exp, const Expr *BlockExp) {
                                     &Context->Idents.get("FuncPtr"),
                                     Context->VoidPtrTy, nullptr,
                                     /*BitWidth=*/nullptr, /*Mutable=*/true,
+                                    /*IsUnnamedSubstructure=*/false,
                                     ICIS_NoInit);
   MemberExpr *ME = new (Context) MemberExpr(PE, true, FD, SourceLocation(),
                                             FD->getType(), VK_LValue,
@@ -3882,6 +3885,7 @@ Stmt *RewriteObjC::RewriteBlockDeclRefExpr(DeclRefExpr *DeclRefExp) {
                                     &Context->Idents.get("__forwarding"), 
                                     Context->VoidPtrTy, nullptr,
                                     /*BitWidth=*/nullptr, /*Mutable=*/true,
+                                    /*IsUnnamedSubstructure=*/false,
                                     ICIS_NoInit);
   MemberExpr *ME = new (Context) MemberExpr(DeclRefExp, isArrow,
                                             FD, SourceLocation(),
@@ -3893,6 +3897,7 @@ Stmt *RewriteObjC::RewriteBlockDeclRefExpr(DeclRefExpr *DeclRefExp) {
                          &Context->Idents.get(Name), 
                          Context->VoidPtrTy, nullptr,
                          /*BitWidth=*/nullptr, /*Mutable=*/true,
+                         /*IsUnnamedSubstructure=*/false,
                          ICIS_NoInit);
   ME = new (Context) MemberExpr(ME, true, FD, SourceLocation(),
                                 DeclRefExp->getType(), VK_LValue, OK_Ordinary);
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp
index b0d1023..c571ee0 100644
--- a/lib/Sema/Sema.cpp
+++ b/lib/Sema/Sema.cpp
@@ -316,6 +316,7 @@ ExprResult Sema::ImpCastExprToType(Expr *E, QualType Ty,
     case CK_LValueToRValue:
     case CK_ArrayToPointerDecay:
     case CK_FunctionToPointerDecay:
+    case CK_UnnamedSubstructurePointer:
     case CK_ToVoid:
       break;
     }
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index b65a04a..99e8f94 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -3269,9 +3269,10 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
     }
   }
 
-  // Check for Microsoft C extension: anonymous struct member.
-  if (getLangOpts().MicrosoftExt && !getLangOpts().CPlusPlus &&
-      CurContext->isRecord() &&
+  // Check for Microsoft C extension: anonymous struct member, and the similar
+  // Plan 9 C extension: unnamed substructures/subunions.
+  if ((getLangOpts().MicrosoftExt || getLangOpts().Plan9Ext) &&
+      !getLangOpts().CPlusPlus && CurContext->isRecord() &&
       DS.getStorageClassSpec() == DeclSpec::SCS_unspecified) {
     // Handle 2 kinds of anonymous struct:
     //   struct STRUCT;
@@ -3281,9 +3282,11 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
     if ((Record && Record->getDeclName() && !Record->isCompleteDefinition()) ||
         (DS.getTypeSpecType() == DeclSpec::TST_typename &&
          DS.getRepAsType().get()->isStructureType())) {
-      Diag(DS.getLocStart(), diag::ext_ms_anonymous_struct)
-        << DS.getSourceRange();
-      return BuildMicrosoftCAnonymousStruct(S, DS, Record);
+      if (getLangOpts().MicrosoftExt) {
+        Diag(DS.getLocStart(), diag::ext_ms_anonymous_struct)
+          << DS.getSourceRange();
+      }
+      return BuildAnonymousStruct(S, DS, Record);
     }
   }
 
@@ -3742,6 +3745,7 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
                              Context.getTypeDeclType(Record),
                              TInfo,
                              /*BitWidth=*/0, /*Mutable=*/false,
+                             /*IsUnnamedSubstructure=*/false,
                              /*InitStyle=*/ICIS_NoInit);
     Anon->setAccess(AS);
     if (getLangOpts().CPlusPlus)
@@ -3807,9 +3811,12 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
   return Anon;
 }
 
-/// BuildMicrosoftCAnonymousStruct - Handle the declaration of an
-/// Microsoft C anonymous structure.
-/// Ref: http://msdn.microsoft.com/en-us/library/z2cx9y4f.aspx
+/// BuildAnonymousStruct - Handle the declaration of a
+/// Microsoft or Plan 9 C anonymous structure.
+/// Ref:
+/// http://msdn.microsoft.com/en-us/library/z2cx9y4f.aspx
+/// http://plan9.bell-labs.com/sys/doc/compiler.html
+///
 /// Example:
 ///
 /// struct A { int a; };
@@ -3820,32 +3827,56 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
 ///   var.a = 3; 
 /// }
 ///
-Decl *Sema::BuildMicrosoftCAnonymousStruct(Scope *S, DeclSpec &DS,
-                                           RecordDecl *Record) {
+Decl *Sema::BuildAnonymousStruct(Scope *S, DeclSpec &DS, RecordDecl *Record) {
+  TypedefNameDecl *Typedef = 0;
   
   // If there is no Record, get the record via the typedef.
-  if (!Record)
+  if (!Record) {
     Record = DS.getRepAsType().get()->getAsStructureType()->getDecl();
+    Typedef = cast<TypedefType>(DS.getRepAsType().get())->getDecl();
+  }
 
   // Mock up a declarator.
   Declarator Dc(DS, Declarator::TypeNameContext);
   TypeSourceInfo *TInfo = GetTypeForDeclarator(Dc, S);
   assert(TInfo && "couldn't build declarator info for anonymous struct");
 
+  IdentifierInfo *Name = 0;
+
+  if (getLangOpts().Plan9Ext && Typedef) {
+    // http://plan9.bell-labs.com/sys/doc/compiler.html
+    // 3.3: "[...] the type name (it must be a typedef) of the unnamed structure
+    // can be used as an identifier."
+    if (CheckAnonMemberRedeclaration(
+            *this, S, CurContext, Typedef->getDeclName(),
+            Typedef->getLocation(), diag::err_anonymous_struct_member_redecl)) {
+      // The Plan 9 compiler accepts such redeclarations, but reject member
+      // references as being ambiguous.
+      return 0;
+    }
+
+    Name = Typedef->getDeclName().getAsIdentifierInfo();
+  }
+
   // Create a declaration for this anonymous struct.
   NamedDecl* Anon = FieldDecl::Create(Context,
-                             cast<RecordDecl>(CurContext),
-                             DS.getLocStart(),
-                             DS.getLocStart(),
-                             /*IdentifierInfo=*/0,
-                             Context.getTypeDeclType(Record),
-                             TInfo,
-                             /*BitWidth=*/0, /*Mutable=*/false,
-                             /*InitStyle=*/ICIS_NoInit);
+                                      cast<RecordDecl>(CurContext),
+                                      DS.getLocStart(),
+                                      DS.getLocStart(),
+                                      /*IdentifierInfo=*/Name,
+                                      Context.getTypeDeclType(Record),
+                                      TInfo,
+                                      /*BitWidth=*/0, /*Mutable=*/false,
+                                      /*IsUnnamedSubstructure=*/true,
+                                      /*InitStyle=*/ICIS_NoInit);
   Anon->setImplicit();
 
   // Add the anonymous struct object to the current context.
-  CurContext->addDecl(Anon);
+  if (Name) {
+    PushOnScopeChains(Anon, S);
+  } else {
+    CurContext->addDecl(Anon);
+  }
 
   // Inject the members of the anonymous struct into the current
   // context and into the identifier resolver chain for name lookup
@@ -11706,7 +11737,9 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T,
     checkDuplicateDefaultInit(*this, cast<CXXRecordDecl>(Record), Loc);
 
   FieldDecl *NewFD = FieldDecl::Create(Context, Record, TSSL, Loc, II, T, TInfo,
-                                       BitWidth, Mutable, InitStyle);
+                                       BitWidth, Mutable,
+                                       /*IsUnnamedSubstructure=*/false,
+                                       InitStyle);
   if (InvalidDecl)
     NewFD->setInvalidDecl();
 
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 33eea16..131f0e4 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -6227,6 +6227,56 @@ Sema::CheckAssignmentConstraints(SourceLocation Loc,
   return CheckAssignmentConstraints(LHSType, RHSPtr, K);
 }
 
+static void FindSubstructurePaths(std::vector<std::vector<FieldDecl *>> &Paths,
+                                  std::vector<FieldDecl *> &CurPath,
+                                  RecordDecl *RD, RecordDecl *Target) {
+  for (FieldDecl *FD : RD->fields()) {
+    if (FD->isUnnamedSubstructure()) {
+      CurPath.push_back(FD);
+      auto FieldRD = FD->getType()->getAs<RecordType>()->getDecl();
+      if (FieldRD == Target) {
+        Paths.push_back(CurPath);
+      } else {
+        FindSubstructurePaths(Paths, CurPath, FieldRD, Target);
+      }
+      CurPath.pop_back();
+    }
+  }
+}
+
+/// Promotes RHS of type RHSType or pointer to RHSType to type LHSType by
+/// following a chain of unnamed substructure references.
+bool Sema::PromoteToUnnamedSubstructure(QualType LHSType, QualType RHSType,
+                                        ExprResult &RHS, bool IsPointer) {
+  auto LHSRType = LHSType->getAs<RecordType>();
+  if (!LHSRType)
+    return false;
+
+  auto RHSRType = RHSType->getAs<RecordType>();
+  if (!RHSRType)
+    return false;
+
+  std::vector<std::vector<FieldDecl *>> Paths;
+  std::vector<FieldDecl *> CurPath;
+  FindSubstructurePaths(Paths, CurPath, RHSRType->getDecl(),
+                        LHSRType->getDecl());
+
+  if (Paths.size() == 1) {
+    bool IsArrow = IsPointer;
+    ExprValueKind VK = IsPointer ? VK_LValue : RHS.get()->getValueKind();
+
+    for (FieldDecl *FD : Paths[0]) {
+      RHS = new (Context) MemberExpr(RHS.get(), IsArrow, FD, SourceLocation(),
+                                     FD->getType(), VK, OK_Ordinary);
+      IsArrow = false;
+    }
+
+    return true;
+  }
+
+  return false;
+}
+
 /// CheckAssignmentConstraints (C99 6.5.16) - This routine currently
 /// has code to accommodate several GCC extensions when type checking
 /// pointers. Here are some objectionable examples that GCC considers warnings:
@@ -6336,9 +6386,24 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS,
   }
 
   // Conversions to normal pointers.
-  if (const PointerType *LHSPointer = dyn_cast<PointerType>(LHSType)) {
+  if (auto LHSPointer = dyn_cast<PointerType>(LHSType)) {
     // U* -> T*
-    if (isa<PointerType>(RHSType)) {
+    if (auto RHSPointer = dyn_cast<PointerType>(RHSType)) {
+      if (getLangOpts().Plan9Ext) {
+        // Implicit conversion from structure pointer to unnamed substructure
+        // pointer.
+        // http://plan9.bell-labs.com/sys/doc/compiler.html
+        // 3.3: "When an outer structure is used in a context that is only legal
+        // for an unnamed substructure, the compiler promotes the reference to
+        // the unnamed substructure. This is true for [...] references to
+        // pointers to structures."
+        if (PromoteToUnnamedSubstructure(LHSPointer->getPointeeType(),
+                                         RHSPointer->getPointeeType(), RHS,
+                                         /*IsPointer=*/true)) {
+          Kind = CK_UnnamedSubstructurePointer;
+          return Compatible;
+        }
+      }
       Kind = CK_BitCast;
       return checkPointerTypesForAssignment(*this, LHSType, RHSType);
     }
@@ -6497,6 +6562,13 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS,
 
   // struct A -> struct B
   if (isa<TagType>(LHSType) && isa<TagType>(RHSType)) {
+    if (getLangOpts().Plan9Ext) {
+      if (PromoteToUnnamedSubstructure(LHSType, RHSType, RHS,
+                                       /*IsPointer=*/false)) {
+        Kind = CK_UnnamedSubstructure;
+        return Compatible;
+      }
+    }
     if (Context.typesAreCompatible(LHSType, RHSType)) {
       Kind = CK_NoOp;
       return Compatible;
@@ -11693,7 +11765,7 @@ static bool captureInCapturedRegion(CapturedRegionScopeInfo *RSI,
     FieldDecl *Field
       = FieldDecl::Create(S.Context, RD, Loc, Loc, 0, CaptureType,
                           S.Context.getTrivialTypeSourceInfo(CaptureType, Loc),
-                          0, false, ICIS_NoInit);
+                          0, false, false, ICIS_NoInit);
     Field->setImplicit(true);
     Field->setAccess(AS_private);
     RD->addDecl(Field);
@@ -11727,7 +11799,7 @@ static ExprResult addAsFieldToClosureType(Sema &S,
   FieldDecl *Field
     = FieldDecl::Create(S.Context, Lambda, Loc, Loc, 0, FieldType,
                         S.Context.getTrivialTypeSourceInfo(FieldType, Loc),
-                        0, false, ICIS_NoInit);
+                        0, false, false, ICIS_NoInit);
   Field->setImplicit(true);
   Field->setAccess(AS_private);
   Lambda->addDecl(Field);
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index bfb209a..879e626 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -781,7 +781,7 @@ static Expr *captureThis(ASTContext &Context, RecordDecl *RD,
   FieldDecl *Field
     = FieldDecl::Create(Context, RD, Loc, Loc, 0, ThisTy,
                         Context.getTrivialTypeSourceInfo(ThisTy, Loc),
-                        0, false, ICIS_NoInit);
+                        0, false, false, ICIS_NoInit);
   Field->setImplicit(true);
   Field->setAccess(AS_private);
   RD->addDecl(Field);
diff --git a/lib/Sema/SemaLambda.cpp b/lib/Sema/SemaLambda.cpp
index e6c714e..da5f754 100644
--- a/lib/Sema/SemaLambda.cpp
+++ b/lib/Sema/SemaLambda.cpp
@@ -819,7 +819,7 @@ VarDecl *Sema::createLambdaInitCaptureVarDecl(SourceLocation Loc,
 FieldDecl *Sema::buildInitCaptureField(LambdaScopeInfo *LSI, VarDecl *Var) {
   FieldDecl *Field = FieldDecl::Create(
       Context, LSI->Lambda, Var->getLocation(), Var->getLocation(),
-      0, Var->getType(), Var->getTypeSourceInfo(), 0, false, ICIS_NoInit);
+      0, Var->getType(), Var->getTypeSourceInfo(), 0, false, false, ICIS_NoInit);
   Field->setImplicit(true);
   Field->setAccess(AS_private);
   LSI->Lambda->addDecl(Field);
diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp
index bb87632..e29b6b9 100644
--- a/lib/Serialization/ASTReaderDecl.cpp
+++ b/lib/Serialization/ASTReaderDecl.cpp
@@ -952,6 +952,7 @@ void ASTDeclReader::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) {
 void ASTDeclReader::VisitFieldDecl(FieldDecl *FD) {
   VisitDeclaratorDecl(FD);
   FD->Mutable = Record[Idx++];
+  FD->IsUnnamedSubstructure = Record[Idx++];
   if (int BitWidthOrInitializer = Record[Idx++]) {
     FD->InitializerOrBitWidth.setInt(BitWidthOrInitializer - 1);
     FD->InitializerOrBitWidth.setPointer(Reader.ReadExpr(F));
diff --git a/lib/Serialization/ASTWriterDecl.cpp b/lib/Serialization/ASTWriterDecl.cpp
index 8a463b5..28a99b3 100644
--- a/lib/Serialization/ASTWriterDecl.cpp
+++ b/lib/Serialization/ASTWriterDecl.cpp
@@ -663,6 +663,7 @@ void ASTDeclWriter::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) {
 void ASTDeclWriter::VisitFieldDecl(FieldDecl *D) {
   VisitDeclaratorDecl(D);
   Record.push_back(D->isMutable());
+  Record.push_back(D->isUnnamedSubstructure());
   if (D->InitializerOrBitWidth.getInt() != ICIS_NoInit ||
       D->InitializerOrBitWidth.getPointer()) {
     Record.push_back(D->InitializerOrBitWidth.getInt() + 1);
@@ -1481,6 +1482,7 @@ void ASTWriter::WriteDeclsBlockAbbrevs() {
   Abv->Add(BitCodeAbbrevOp(0));                       // hasExtInfo
   // FieldDecl
   Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isMutable
+  Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isUnnamedSubstructure
   Abv->Add(BitCodeAbbrevOp(0));                       //getBitWidth
   // Type Source Info
   Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6));
@@ -1513,6 +1515,7 @@ void ASTWriter::WriteDeclsBlockAbbrevs() {
   Abv->Add(BitCodeAbbrevOp(0));                       // hasExtInfo
   // FieldDecl
   Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isMutable
+  Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isUnnamedSubstructure
   Abv->Add(BitCodeAbbrevOp(0));                       //getBitWidth
   // ObjC Ivar
   Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // getAccessControl
diff --git a/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/lib/StaticAnalyzer/Core/ExprEngineC.cpp
index b754ecb..df6d340 100644
--- a/lib/StaticAnalyzer/Core/ExprEngineC.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngineC.cpp
@@ -318,7 +318,9 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
       case CK_AnyPointerToBlockPointerCast:  
       case CK_ObjCObjectLValueCast: 
       case CK_ZeroToOCLEvent:
-      case CK_LValueBitCast: {
+      case CK_LValueBitCast:
+      case CK_UnnamedSubstructure:
+      case CK_UnnamedSubstructurePointer: {
         // Delegate to SValBuilder to process.
         SVal V = state->getSVal(Ex, LCtx);
         V = svalBuilder.evalCast(V, T, ExTy);
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to