diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h
index 6348ce6..3ce5d15 100644
--- a/include/clang/AST/Decl.h
+++ b/include/clang/AST/Decl.h
@@ -925,9 +925,16 @@ public:
   void defineBody(ASTContext& C, FieldDecl **Members, unsigned numMembers);
 
   /// getMember - If the member doesn't exist, or there are no members, this 
-  /// function will return 0;
+  /// function will return 0. Does not search inner unnamed records.
   FieldDecl *getMember(IdentifierInfo *name);
 
+  /// getMemberChain - Returns a series of FieldDecls that describes the
+  /// fields in which this member is located. Normally there will be only be
+  /// one such FieldDecl, but if the member is located inside one or more inner
+  /// unnamed structs or unions, then the chain will have multiple entries.
+  bool getMemberChain(IdentifierInfo *II, llvm::SmallVector<FieldDecl *, 4> &
+      Chain);
+
   static bool classof(const Decl *D) {
     return D->getKind() >= RecordFirst && D->getKind() <= RecordLast;
   }
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index b0fe4d1..bbf2fcb 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -291,9 +291,39 @@ FieldDecl *RecordDecl::getMember(IdentifierInfo *II) {
   for (int i = 0; i != NumMembers; ++i)
     if (Members[i]->getIdentifier() == II)
       return Members[i];
+
   return 0;
 }
 
+bool RecordDecl::getMemberChain(IdentifierInfo *II,
+    llvm::SmallVector<FieldDecl *, 4> &Chain) {
+  FieldDecl *FD;
+  
+  if (Members == 0 || NumMembers < 0)
+    return false;
+
+  FD = getMember(II);
+  if (FD) {
+    Chain.insert(Chain.begin(), FD);
+    return true;
+  } else {
+    // Recurse through the inner unnamed records.
+    for (int i = 0; i < NumMembers; ++i) {
+      if (!Members[i]->getIdentifier()) {
+        Type &ty = *Members[i]->getType();
+        if (ty.isRecordType()
+            && ty.getAsRecordType()->getDecl()->getMemberChain(II, Chain)) {
+          // We found the inner unnamed record that contains the field.
+          Chain.insert(Chain.begin(), Members[i]);
+          return true;
+        }
+      }
+    }
+  }
+
+  return false;
+}
+
 //===----------------------------------------------------------------------===//
 // BlockDecl Implementation
 //===----------------------------------------------------------------------===//
diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp
index 420bdbd..61a30a0 100644
--- a/lib/AST/StmtPrinter.cpp
+++ b/lib/AST/StmtPrinter.cpp
@@ -690,11 +690,20 @@ void StmtPrinter::VisitCallExpr(CallExpr *Call) {
 }
 void StmtPrinter::VisitMemberExpr(MemberExpr *Node) {
   PrintExpr(Node->getBase());
-  OS << (Node->isArrow() ? "->" : ".");
-  
+
   FieldDecl *Field = Node->getMemberDecl();
-  assert(Field && "MemberExpr should alway reference a field!");
-  OS << Field->getName();
+  assert(Field && "MemberExpr should always reference a field!");
+
+  // Is this the field that was actually selected? (If this is not true, this
+  // is an access to an unnamed field and we shouldn't print anything.)
+  if (Field->getIdentifier()) {
+    MemberExpr *Member = Node;
+    while (isa<MemberExpr>(Member->getBase()))
+      Member = cast<MemberExpr>(Member->getBase());
+    OS << (Member->isArrow() ? "->" : ".");
+
+    OS << Field->getName();
+  }
 }
 void StmtPrinter::VisitExtVectorElementExpr(ExtVectorElementExpr *Node) {
   PrintExpr(Node->getBase());
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index 2b18be0..b1db736 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -768,9 +768,14 @@ ParseStructDeclaration(DeclSpec &DS,
   SourceLocation DSStart = Tok.getLocation();
   ParseSpecifierQualifierList(DS);
   
-  // If there are no declarators, issue a warning.
+  // If there are no declarators, issue a warning... unless it's a struct or
+  // union, in which case it's an unnamed record and we let it through.
   if (Tok.is(tok::semi)) {
-    Diag(DSStart, diag::w_no_declarators);
+    if (DS.getTypeSpecType() == DeclSpec::TST_struct
+      || DS.getTypeSpecType() == DeclSpec::TST_union)
+      Fields.push_back(FieldDeclarator(DS));
+    else
+      Diag(DSStart, diag::w_no_declarators);
     return;
   }
 
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 18d77c4..dd2484f 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -2377,10 +2377,10 @@ Sema::DeclTy *Sema::ActOnField(Scope *S,
   Expr *BitWidth = (Expr*)BitfieldWidth;
   SourceLocation Loc = DeclStart;
   if (II) Loc = D.getIdentifierLoc();
-  
-  // FIXME: Unnamed fields can be handled in various different ways, for
-  // example, unnamed unions inject all members into the struct namespace!
-    
+
+  // Unnamed structs and unions are handled specially when fields are resolved.
+  // They aren't specially handled here. 
+
   if (BitWidth) {
     // TODO: Validate.
     //printf("WARNING: BITFIELDS IGNORED!\n");
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index d3650c8..a3445ae 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -908,21 +908,31 @@ ActOnMemberReferenceExpr(ExprTy *Base, SourceLocation OpLoc,
     if (RTy->isIncompleteType())
       return Diag(OpLoc, diag::err_typecheck_incomplete_tag, RDecl->getName(),
                   BaseExpr->getSourceRange());
+
     // The record definition is complete, now make sure the member is valid.
-    FieldDecl *MemberDecl = RDecl->getMember(&Member);
-    if (!MemberDecl)
+    llvm::SmallVector<FieldDecl *, 4> Chain;
+    if (!RDecl->getMemberChain(&Member, Chain))
       return Diag(MemberLoc, diag::err_typecheck_no_member, Member.getName(),
                   BaseExpr->getSourceRange());
 
-    // Figure out the type of the member; see C99 6.5.2.3p3
-    // FIXME: Handle address space modifiers
-    QualType MemberType = MemberDecl->getType();
-    unsigned combinedQualifiers =
-        MemberType.getCVRQualifiers() | BaseType.getCVRQualifiers();
-    MemberType = MemberType.getQualifiedType(combinedQualifiers);
+    // Build up the chain of member dereferences.
+    for (llvm::SmallVector<FieldDecl *, 4>::iterator I = Chain.begin();
+        I != Chain.end(); ++I) {
+      // Figure out the type of the member; see C99 6.5.2.3p3
+      // FIXME: Handle address space modifiers
+      FieldDecl *MemberDecl = *I;
+      QualType MemberType = MemberDecl->getType();
+      unsigned combinedQualifiers =
+          MemberType.getCVRQualifiers() | BaseType.getCVRQualifiers();
+      MemberType = MemberType.getQualifiedType(combinedQualifiers);
+
+      int isArrow = I == Chain.begin() && OpKind == tok::arrow;
+      BaseExpr = new MemberExpr(BaseExpr, isArrow, MemberDecl, MemberLoc,
+          MemberType);
+      BaseType = MemberType;
+    }
 
-    return new MemberExpr(BaseExpr, OpKind == tok::arrow, MemberDecl,
-                          MemberLoc, MemberType);
+    return BaseExpr;
   }
   
   // Handle access to Objective-C instance variables, such as "Obj->ivar" and
