Implement support for C++11 in-class initialization of non-static data members.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@132878 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index c2fee32..9446c0e 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -2610,7 +2610,8 @@
                              /*IdentifierInfo=*/0,
                              Context.getTypeDeclType(Record),
                              TInfo,
-                             /*BitWidth=*/0, /*Mutable=*/false);
+                             /*BitWidth=*/0, /*Mutable=*/false,
+                             /*HasInit=*/false);
     Anon->setAccess(AS);
     if (getLangOptions().CPlusPlus)
       FieldCollector->Add(cast<FieldDecl>(Anon));
@@ -2700,7 +2701,8 @@
                              /*IdentifierInfo=*/0,
                              Context.getTypeDeclType(Record),
                              TInfo,
-                             /*BitWidth=*/0, /*Mutable=*/false);
+                             /*BitWidth=*/0, /*Mutable=*/false,
+                             /*HasInit=*/false);
   Anon->setImplicit();
 
   // Add the anonymous struct object to the current context.
@@ -7512,14 +7514,13 @@
   return false;
 }
 
-/// ActOnField - Each field of a struct/union/class is passed into this in order
+/// ActOnField - Each field of a C struct/union is passed into this in order
 /// to create a FieldDecl object for it.
-Decl *Sema::ActOnField(Scope *S, Decl *TagD,
-                                 SourceLocation DeclStart,
-                                 Declarator &D, ExprTy *BitfieldWidth) {
+Decl *Sema::ActOnField(Scope *S, Decl *TagD, SourceLocation DeclStart,
+                       Declarator &D, ExprTy *BitfieldWidth) {
   FieldDecl *Res = HandleField(S, cast_or_null<RecordDecl>(TagD),
                                DeclStart, D, static_cast<Expr*>(BitfieldWidth),
-                               AS_public);
+                               /*HasInit=*/false, AS_public);
   return Res;
 }
 
@@ -7527,7 +7528,7 @@
 ///
 FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record,
                              SourceLocation DeclStart,
-                             Declarator &D, Expr *BitWidth,
+                             Declarator &D, Expr *BitWidth, bool HasInit,
                              AccessSpecifier AS) {
   IdentifierInfo *II = D.getIdentifier();
   SourceLocation Loc = DeclStart;
@@ -7576,8 +7577,8 @@
     = (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_mutable);
   SourceLocation TSSL = D.getSourceRange().getBegin();
   FieldDecl *NewFD
-    = CheckFieldDecl(II, T, TInfo, Record, Loc, Mutable, BitWidth, TSSL,
-                     AS, PrevDecl, &D);
+    = CheckFieldDecl(II, T, TInfo, Record, Loc, Mutable, BitWidth, HasInit,
+                     TSSL, AS, PrevDecl, &D);
 
   if (NewFD->isInvalidDecl())
     Record->setInvalidDecl();
@@ -7606,7 +7607,7 @@
 FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T,
                                 TypeSourceInfo *TInfo,
                                 RecordDecl *Record, SourceLocation Loc,
-                                bool Mutable, Expr *BitWidth,
+                                bool Mutable, Expr *BitWidth, bool HasInit,
                                 SourceLocation TSSL,
                                 AccessSpecifier AS, NamedDecl *PrevDecl,
                                 Declarator *D) {
@@ -7686,7 +7687,7 @@
   }
 
   FieldDecl *NewFD = FieldDecl::Create(Context, Record, TSSL, Loc, II, T, TInfo,
-                                       BitWidth, Mutable);
+                                       BitWidth, Mutable, HasInit);
   if (InvalidDecl)
     NewFD->setInvalidDecl();
 
@@ -8289,16 +8290,17 @@
 
     // Now that the record is complete, do any delayed exception spec checks
     // we were missing.
-    if (!DelayedDestructorExceptionSpecChecks.empty()) {
+    while (!DelayedDestructorExceptionSpecChecks.empty()) {
       const CXXDestructorDecl *Dtor =
               DelayedDestructorExceptionSpecChecks.back().first;
-      if (Dtor->getParent() == Record) {
-        assert(!Dtor->getParent()->isDependentType() &&
-            "Should not ever add destructors of templates into the list.");
-        CheckOverridingFunctionExceptionSpec(Dtor,
-            DelayedDestructorExceptionSpecChecks.back().second);
-        DelayedDestructorExceptionSpecChecks.pop_back();
-      }
+      if (Dtor->getParent() != Record)
+        break;
+
+      assert(!Dtor->getParent()->isDependentType() &&
+          "Should not ever add destructors of templates into the list.");
+      CheckOverridingFunctionExceptionSpec(Dtor,
+          DelayedDestructorExceptionSpecChecks.back().second);
+      DelayedDestructorExceptionSpecChecks.pop_back();
     }
 
   } else {
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index a4ba5fa..ce99efb 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -113,8 +113,8 @@
 
 void Sema::ImplicitExceptionSpecification::CalledDecl(CXXMethodDecl *Method) {
   assert(Context && "ImplicitExceptionSpecification without an ASTContext");
-  // If we have an MSAny spec already, don't bother.
-  if (!Method || ComputedEST == EST_MSAny)
+  // If we have an MSAny or unknown spec already, don't bother.
+  if (!Method || ComputedEST == EST_MSAny || ComputedEST == EST_Delayed)
     return;
 
   const FunctionProtoType *Proto
@@ -123,12 +123,15 @@
   ExceptionSpecificationType EST = Proto->getExceptionSpecType();
 
   // If this function can throw any exceptions, make a note of that.
-  if (EST == EST_MSAny || EST == EST_None) {
+  if (EST == EST_Delayed || EST == EST_MSAny || EST == EST_None) {
     ClearExceptions();
     ComputedEST = EST;
     return;
   }
 
+  // FIXME: If the call to this decl is using any of its default arguments, we
+  // need to search them for potentially-throwing calls.
+
   // If this function has a basic noexcept, it doesn't affect the outcome.
   if (EST == EST_BasicNoexcept)
     return;
@@ -175,6 +178,35 @@
       Exceptions.push_back(*E);
 }
 
+void Sema::ImplicitExceptionSpecification::CalledExpr(Expr *E) {
+  if (!E || ComputedEST == EST_MSAny || ComputedEST == EST_Delayed)
+    return;
+
+  // FIXME:
+  //
+  // C++0x [except.spec]p14:
+  //   [An] implicit exception-specification specifies the type-id T if and
+  // only if T is allowed by the exception-specification of a function directly
+  // invoked by f’s implicit definition; f shall allow all exceptions if any
+  // function it directly invokes allows all exceptions, and f shall allow no
+  // exceptions if every function it directly invokes allows no exceptions.
+  //
+  // Note in particular that if an implicit exception-specification is generated
+  // for a function containing a throw-expression, that specification can still
+  // be noexcept(true).
+  //
+  // Note also that 'directly invoked' is not defined in the standard, and there
+  // is no indication that we should only consider potentially-evaluated calls.
+  //
+  // Ultimately we should implement the intent of the standard: the exception
+  // specification should be the set of exceptions which can be thrown by the
+  // implicit definition. For now, we assume that any non-nothrow expression can
+  // throw any exception.
+
+  if (E->CanThrow(*Context))
+    ComputedEST = EST_None;
+}
+
 bool
 Sema::SetParamDefaultArgument(ParmVarDecl *Param, Expr *Arg,
                               SourceLocation EqualLoc) {
@@ -1029,13 +1061,15 @@
 
 /// ActOnCXXMemberDeclarator - This is invoked when a C++ class member
 /// declarator is parsed. 'AS' is the access specifier, 'BW' specifies the
-/// bitfield width if there is one and 'InitExpr' specifies the initializer if
-/// any.
+/// bitfield width if there is one, 'InitExpr' specifies the initializer if
+/// one has been parsed, and 'HasDeferredInit' is true if an initializer is
+/// present but parsing it has been deferred.
 Decl *
 Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
                                MultiTemplateParamsArg TemplateParameterLists,
                                ExprTy *BW, const VirtSpecifiers &VS,
-                               ExprTy *InitExpr, bool IsDefinition) {
+                               ExprTy *InitExpr, bool HasDeferredInit,
+                               bool IsDefinition) {
   const DeclSpec &DS = D.getDeclSpec();
   DeclarationNameInfo NameInfo = GetNameForDeclarator(D);
   DeclarationName Name = NameInfo.getName();
@@ -1050,6 +1084,7 @@
 
   assert(isa<CXXRecordDecl>(CurContext));
   assert(!DS.isFriendSpecified());
+  assert(!Init || !HasDeferredInit);
 
   bool isFunc = false;
   if (D.isFunctionDeclarator())
@@ -1121,9 +1156,11 @@
     // FIXME: Check for template parameters!
     // FIXME: Check that the name is an identifier!
     Member = HandleField(S, cast<CXXRecordDecl>(CurContext), Loc, D, BitWidth,
-                         AS);
+                         HasDeferredInit, AS);
     assert(Member && "HandleField never returns null");
   } else {
+    assert(!HasDeferredInit);
+
     Member = HandleDeclarator(S, D, move(TemplateParameterLists), IsDefinition);
     if (!Member) {
       return 0;
@@ -1194,6 +1231,14 @@
   if (Init)
     AddInitializerToDecl(Member, Init, false,
                          DS.getTypeSpecType() == DeclSpec::TST_auto);
+  else if (DS.getTypeSpecType() == DeclSpec::TST_auto &&
+           DS.getStorageClassSpec() == DeclSpec::SCS_static) {
+    // C++0x [dcl.spec.auto]p4: 'auto' can only be used in the type of a static
+    // data member if a brace-or-equal-initializer is provided.
+    Diag(Loc, diag::err_auto_var_requires_init)
+      << Name << cast<ValueDecl>(Member)->getType();
+    Member->setInvalidDecl();
+  }
 
   FinalizeDeclaration(Member);
 
@@ -1202,6 +1247,47 @@
   return Member;
 }
 
+/// ActOnCXXInClassMemberInitializer - This is invoked after parsing an
+/// in-class initializer for a non-static C++ class member. Such parsing
+/// is deferred until the class is complete.
+void
+Sema::ActOnCXXInClassMemberInitializer(Decl *D, SourceLocation EqualLoc,
+                                       Expr *InitExpr) {
+  FieldDecl *FD = cast<FieldDecl>(D);
+
+  if (!InitExpr) {
+    FD->setInvalidDecl();
+    FD->removeInClassInitializer();
+    return;
+  }
+
+  ExprResult Init = InitExpr;
+  if (!FD->getType()->isDependentType() && !InitExpr->isTypeDependent()) {
+    // FIXME: if there is no EqualLoc, this is list-initialization.
+    Init = PerformCopyInitialization(
+      InitializedEntity::InitializeMember(FD), EqualLoc, InitExpr);
+    if (Init.isInvalid()) {
+      FD->setInvalidDecl();
+      return;
+    }
+
+    CheckImplicitConversions(Init.get(), EqualLoc);
+  }
+
+  // C++0x [class.base.init]p7:
+  //   The initialization of each base and member constitutes a
+  //   full-expression.
+  Init = MaybeCreateExprWithCleanups(Init);
+  if (Init.isInvalid()) {
+    FD->setInvalidDecl();
+    return;
+  }
+
+  InitExpr = Init.release();
+
+  FD->setInClassInitializer(InitExpr);
+}
+
 /// \brief Find the direct and/or virtual base specifiers that
 /// correspond to the given base type, for use in base initialization
 /// within a constructor.
@@ -2073,7 +2159,7 @@
 };
 }
 
-static bool CollectFieldInitializer(BaseAndFieldInfo &Info,
+static bool CollectFieldInitializer(Sema &SemaRef, BaseAndFieldInfo &Info,
                                     FieldDecl *Top, FieldDecl *Field) {
 
   // Overwhelmingly common case: we have a direct initializer for this field.
@@ -2082,6 +2168,18 @@
     return false;
   }
 
+  // C++0x [class.base.init]p8: if the entity is a non-static data member that
+  // has a brace-or-equal-initializer, the entity is initialized as specified
+  // in [dcl.init].
+  if (Field->hasInClassInitializer()) {
+    Info.AllToInit.push_back(
+      new (SemaRef.Context) CXXCtorInitializer(SemaRef.Context, Field,
+                                               SourceLocation(),
+                                               SourceLocation(), 0,
+                                               SourceLocation()));
+    return false;
+  }
+
   if (Info.IIK == IIK_Default && Field->isAnonymousStructOrUnion()) {
     const RecordType *FieldClassType = Field->getType()->getAs<RecordType>();
     assert(FieldClassType && "anonymous struct/union without record type");
@@ -2104,7 +2202,7 @@
           // field in the class is also initialized, so exit immediately.
           return false;
         } else if ((*FA)->isAnonymousStructOrUnion()) {
-          if (CollectFieldInitializer(Info, Top, *FA))
+          if (CollectFieldInitializer(SemaRef, Info, Top, *FA))
             return true;
         }
       }
@@ -2119,7 +2217,7 @@
       // necessary.
       for (RecordDecl::field_iterator FA = FieldClassDecl->field_begin(),
            EA = FieldClassDecl->field_end(); FA != EA; FA++) {
-        if (CollectFieldInitializer(Info, Top, *FA))
+        if (CollectFieldInitializer(SemaRef, Info, Top, *FA))
           return true;
       }
     }
@@ -2128,7 +2226,7 @@
   // Don't try to build an implicit initializer if there were semantic
   // errors in any of the initializers (and therefore we might be
   // missing some that the user actually wrote).
-  if (Info.AnyErrorsInInits)
+  if (Info.AnyErrorsInInits || Field->isInvalidDecl())
     return false;
 
   CXXCtorInitializer *Init = 0;
@@ -2260,7 +2358,7 @@
              "Incomplete array type is not valid");
       continue;
     }
-    if (CollectFieldInitializer(Info, *Field, *Field))
+    if (CollectFieldInitializer(*this, Info, *Field, *Field))
       HadError = true;
   }
 
@@ -2939,6 +3037,9 @@
     for (RecordDecl::field_iterator F = Record->field_begin(), 
                                  FEnd = Record->field_end();
          F != FEnd; ++F) {
+      if (F->hasInClassInitializer())
+        continue;
+
       if (F->getType()->isReferenceType() ||
           (F->getType().isConstQualified() && F->getType()->isScalarType())) {
         if (!Complained) {
@@ -3066,6 +3167,11 @@
   ImplicitExceptionSpecification Spec
     = ComputeDefaultedDefaultCtorExceptionSpec(CD->getParent());
   FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI();
+  if (EPI.ExceptionSpecType == EST_Delayed) {
+    // Exception specification depends on some deferred part of the class. We'll
+    // try again when the class's definition has been fully processed.
+    return;
+  }
   const FunctionProtoType *CtorType = CD->getType()->getAs<FunctionProtoType>(),
                           *ExceptionType = Context.getFunctionType(
                          Context.VoidTy, 0, 0, EPI)->getAs<FunctionProtoType>();
@@ -3383,12 +3489,15 @@
   for (CXXRecordDecl::field_iterator FI = RD->field_begin(),
                                      FE = RD->field_end();
        FI != FE; ++FI) {
+    if (FI->isInvalidDecl())
+      continue;
+    
     QualType FieldType = Context.getBaseElementType(FI->getType());
     CXXRecordDecl *FieldRecord = FieldType->getAsCXXRecordDecl();
-    
+
     // -- any non-static data member with no brace-or-equal-initializer is of
     //    reference type
-    if (FieldType->isReferenceType())
+    if (FieldType->isReferenceType() && !FI->hasInClassInitializer())
       return true;
 
     // -- X is a union and all its variant members are of const-qualified type
@@ -3413,6 +3522,7 @@
       //    array thereof) with no brace-or-equal-initializer does not have a
       //    user-provided default constructor
       if (FieldType.isConstQualified() &&
+          !FI->hasInClassInitializer() &&
           !FieldRecord->hasUserProvidedDefaultConstructor())
         return true;
  
@@ -3445,18 +3555,21 @@
         continue;
       }
 
-      // -- any non-static data member ... has class type M (or array thereof)
-      //    and either M has no default constructor or overload resolution as
-      //    applied to M's default constructor results in an ambiguity or in a
-      //    function that is deleted or inaccessible from the defaulted default
-      //    constructor.
-      CXXConstructorDecl *FieldDefault = LookupDefaultConstructor(FieldRecord);
-      if (!FieldDefault || FieldDefault->isDeleted())
-        return true;
-      if (CheckConstructorAccess(Loc, FieldDefault, FieldDefault->getAccess(),
-                                 PDiag()) != AR_accessible)
-        return true;
-    } else if (!Union && FieldType.isConstQualified()) {
+      // -- any non-static data member with no brace-or-equal-initializer has
+      //    class type M (or array thereof) and either M has no default
+      //    constructor or overload resolution as applied to M's default
+      //    constructor results in an ambiguity or in a function that is deleted
+      //    or inaccessible from the defaulted default constructor.
+      if (!FI->hasInClassInitializer()) {
+        CXXConstructorDecl *FieldDefault = LookupDefaultConstructor(FieldRecord);
+        if (!FieldDefault || FieldDefault->isDeleted())
+          return true;
+        if (CheckConstructorAccess(Loc, FieldDefault, FieldDefault->getAccess(),
+                                   PDiag()) != AR_accessible)
+          return true;
+      }
+    } else if (!Union && FieldType.isConstQualified() &&
+               !FI->hasInClassInitializer()) {
       // -- any non-variant non-static data member of const-qualified type (or
       //    array thereof) with no brace-or-equal-initializer does not have a
       //    user-provided default constructor
@@ -5905,7 +6018,12 @@
   for (RecordDecl::field_iterator F = ClassDecl->field_begin(),
                                FEnd = ClassDecl->field_end();
        F != FEnd; ++F) {
-    if (const RecordType *RecordTy
+    if (F->hasInClassInitializer()) {
+      if (Expr *E = F->getInClassInitializer())
+        ExceptSpec.CalledExpr(E);
+      else if (!F->isInvalidDecl())
+        ExceptSpec.SetDelayed();
+    } else if (const RecordType *RecordTy
               = Context.getBaseElementType(F->getType())->getAs<RecordType>()) {
       CXXRecordDecl *FieldRecDecl = cast<CXXRecordDecl>(RecordTy->getDecl());
       CXXConstructorDecl *Constructor = LookupDefaultConstructor(FieldRecDecl);
@@ -6001,6 +6119,59 @@
   }
 }
 
+/// Get any existing defaulted default constructor for the given class. Do not
+/// implicitly define one if it does not exist.
+static CXXConstructorDecl *getDefaultedDefaultConstructorUnsafe(Sema &Self,
+                                                             CXXRecordDecl *D) {
+  ASTContext &Context = Self.Context;
+  QualType ClassType = Context.getTypeDeclType(D);
+  DeclarationName ConstructorName
+    = Context.DeclarationNames.getCXXConstructorName(
+                      Context.getCanonicalType(ClassType.getUnqualifiedType()));
+
+  DeclContext::lookup_const_iterator Con, ConEnd;
+  for (llvm::tie(Con, ConEnd) = D->lookup(ConstructorName);
+       Con != ConEnd; ++Con) {
+    // A function template cannot be defaulted.
+    if (isa<FunctionTemplateDecl>(*Con))
+      continue;
+
+    CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(*Con);
+    if (Constructor->isDefaultConstructor())
+      return Constructor->isDefaulted() ? Constructor : 0;
+  }
+  return 0;
+}
+
+void Sema::ActOnFinishDelayedMemberInitializers(Decl *D) {
+  if (!D) return;
+  AdjustDeclIfTemplate(D);
+
+  CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(D);
+  CXXConstructorDecl *CtorDecl
+    = getDefaultedDefaultConstructorUnsafe(*this, ClassDecl);
+
+  if (!CtorDecl) return;
+
+  // Compute the exception specification for the default constructor.
+  const FunctionProtoType *CtorTy =
+    CtorDecl->getType()->castAs<FunctionProtoType>();
+  if (CtorTy->getExceptionSpecType() == EST_Delayed) {
+    ImplicitExceptionSpecification Spec = 
+      ComputeDefaultedDefaultCtorExceptionSpec(ClassDecl);
+    FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI();
+    assert(EPI.ExceptionSpecType != EST_Delayed);
+
+    CtorDecl->setType(Context.getFunctionType(Context.VoidTy, 0, 0, EPI));
+  }
+
+  // If the default constructor is explicitly defaulted, checking the exception
+  // specification is deferred until now.
+  if (!CtorDecl->isInvalidDecl() && CtorDecl->isExplicitlyDefaulted() &&
+      !ClassDecl->isDependentType())
+    CheckExplicitlyDefaultedDefaultConstructor(CtorDecl);
+}
+
 void Sema::DeclareInheritedConstructors(CXXRecordDecl *ClassDecl) {
   // We start with an initial pass over the base classes to collect those that
   // inherit constructors from. If there are none, we can forgo all further
@@ -6094,7 +6265,9 @@
         // Build up a function type for this particular constructor.
         // FIXME: The working paper does not consider that the exception spec
         // for the inheriting constructor might be larger than that of the
-        // source. This code doesn't yet, either.
+        // source. This code doesn't yet, either. When it does, this code will
+        // need to be delayed until after exception specifications and in-class
+        // member initializers are attached.
         const Type *NewCtorType;
         if (params == maxParams)
           NewCtorType = BaseCtorType;
diff --git a/lib/Sema/SemaExceptionSpec.cpp b/lib/Sema/SemaExceptionSpec.cpp
index 0f6108c..7bcec31 100644
--- a/lib/Sema/SemaExceptionSpec.cpp
+++ b/lib/Sema/SemaExceptionSpec.cpp
@@ -298,8 +298,6 @@
   //   - both are non-throwing, regardless of their form,
   //   - both have the form noexcept(constant-expression) and the constant-
   //     expressions are equivalent,
-  //   - one exception-specification is a noexcept-specification allowing all
-  //     exceptions and the other is of the form throw(type-id-list), or
   //   - both are dynamic-exception-specifications that have the same set of
   //     adjusted types.
   //
@@ -307,8 +305,6 @@
   //   of the form throw(), noexcept, or noexcept(constant-expression) where the
   //   constant-expression yields true.
   //
-  // CWG 1073 Proposed resolution: Strike the third bullet above.
-  //
   // C++0x [except.spec]p4: If any declaration of a function has an exception-
   //   specifier that is not a noexcept-specification allowing all exceptions,
   //   all declarations [...] of that function shall have a compatible
@@ -320,6 +316,9 @@
   ExceptionSpecificationType OldEST = Old->getExceptionSpecType();
   ExceptionSpecificationType NewEST = New->getExceptionSpecType();
 
+  assert(OldEST != EST_Delayed && NewEST != EST_Delayed &&
+         "Shouldn't see unknown exception specifications here");
+
   // Shortcut the case where both have no spec.
   if (OldEST == EST_None && NewEST == EST_None)
     return false;
@@ -506,6 +505,9 @@
 
   ExceptionSpecificationType SubEST = Subset->getExceptionSpecType();
 
+  assert(SuperEST != EST_Delayed && SubEST != EST_Delayed &&
+         "Shouldn't see unknown exception specifications here");
+
   // It does not. If the subset contains everything, we've failed.
   if (SubEST == EST_None || SubEST == EST_MSAny) {
     Diag(SubLoc, DiagID);
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index dafd56b..0549e94 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -1333,8 +1333,8 @@
     // We've found a member of an anonymous struct/union that is
     // inside a non-anonymous struct/union, so in a well-formed
     // program our base object expression is "this".
-    CXXMethodDecl *method = tryCaptureCXXThis();
-    if (!method) {
+    QualType ThisTy = getAndCaptureCurrentThisType();
+    if (ThisTy.isNull()) {
       Diag(loc, diag::err_invalid_member_use_in_static_method)
         << indirectField->getDeclName();
       return ExprError();
@@ -1342,10 +1342,9 @@
 
     // Our base object expression is "this".
     baseObjectExpr =
-      new (Context) CXXThisExpr(loc, method->getThisType(Context),
-                                /*isImplicit=*/ true);
+      new (Context) CXXThisExpr(loc, ThisTy, /*isImplicit=*/ true);
     baseObjectIsPointer = true;
-    baseQuals = Qualifiers::fromCVRMask(method->getTypeQualifiers());
+    baseQuals = ThisTy->castAs<PointerType>()->getPointeeType().getQualifiers();
   }
 
   // Build the implicit member references to the field of the
@@ -1492,14 +1491,23 @@
 /// conservatively answer "yes", in which case some errors will simply
 /// not be caught until template-instantiation.
 static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef,
+                                            Scope *CurScope,
                                             const LookupResult &R) {
   assert(!R.empty() && (*R.begin())->isCXXClassMember());
 
   DeclContext *DC = SemaRef.getFunctionLevelDeclContext();
+
   bool isStaticContext =
     (!isa<CXXMethodDecl>(DC) ||
      cast<CXXMethodDecl>(DC)->isStatic());
 
+  // C++0x [expr.prim]p4:
+  //   Otherwise, if a member-declarator declares a non-static data member
+  // of a class X, the expression this is a prvalue of type "pointer to X"
+  // within the optional brace-or-equal-initializer.
+  if (CurScope->getFlags() & Scope::ThisScope)
+    isStaticContext = false;
+
   if (R.isUnresolvableResult())
     return isStaticContext ? IMA_Unresolved_StaticContext : IMA_Unresolved;
 
@@ -1547,8 +1555,11 @@
     return IMA_Error_StaticContext;
   }
 
-  CXXRecordDecl *
-        contextClass = cast<CXXMethodDecl>(DC)->getParent()->getCanonicalDecl();
+  CXXRecordDecl *contextClass;
+  if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(DC))
+    contextClass = MD->getParent()->getCanonicalDecl();
+  else
+    contextClass = cast<CXXRecordDecl>(DC);
 
   // [class.mfct.non-static]p3: 
   // ...is used in the body of a non-static member function of class X,
@@ -2026,7 +2037,7 @@
 Sema::BuildPossibleImplicitMemberExpr(const CXXScopeSpec &SS,
                                       LookupResult &R,
                                 const TemplateArgumentListInfo *TemplateArgs) {
-  switch (ClassifyImplicitMemberAccess(*this, R)) {
+  switch (ClassifyImplicitMemberAccess(*this, CurScope, R)) {
   case IMA_Instance:
     return BuildImplicitMemberExpr(SS, R, TemplateArgs, true);
 
@@ -2469,19 +2480,18 @@
   // If this is known to be an instance access, go ahead and build an
   // implicit 'this' expression now.
   // 'this' expression now.
-  CXXMethodDecl *method = tryCaptureCXXThis();
-  assert(method && "didn't correctly pre-flight capture of 'this'");
+  QualType ThisTy = getAndCaptureCurrentThisType();
+  assert(!ThisTy.isNull() && "didn't correctly pre-flight capture of 'this'");
 
-  QualType thisType = method->getThisType(Context);
   Expr *baseExpr = 0; // null signifies implicit access
   if (IsKnownInstance) {
     SourceLocation Loc = R.getNameLoc();
     if (SS.getRange().isValid())
       Loc = SS.getRange().getBegin();
-    baseExpr = new (Context) CXXThisExpr(loc, thisType, /*isImplicit=*/true);
+    baseExpr = new (Context) CXXThisExpr(loc, ThisTy, /*isImplicit=*/true);
   }
 
-  return BuildMemberReferenceExpr(baseExpr, thisType,
+  return BuildMemberReferenceExpr(baseExpr, ThisTy,
                                   /*OpLoc*/ SourceLocation(),
                                   /*IsArrow*/ true,
                                   SS,
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index 50462ab..2f5a890 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -17,6 +17,7 @@
 #include "clang/Sema/Lookup.h"
 #include "clang/Sema/ParsedTemplate.h"
 #include "clang/Sema/ScopeInfo.h"
+#include "clang/Sema/Scope.h"
 #include "clang/Sema/TemplateDeduction.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/CXXInheritance.h"
@@ -575,42 +576,54 @@
   return Owned(E);
 }
 
-CXXMethodDecl *Sema::tryCaptureCXXThis() {
+QualType Sema::getAndCaptureCurrentThisType() {
   // Ignore block scopes: we can capture through them.
   // Ignore nested enum scopes: we'll diagnose non-constant expressions
   // where they're invalid, and other uses are legitimate.
   // Don't ignore nested class scopes: you can't use 'this' in a local class.
   DeclContext *DC = CurContext;
+  unsigned NumBlocks = 0;
   while (true) {
-    if (isa<BlockDecl>(DC)) DC = cast<BlockDecl>(DC)->getDeclContext();
-    else if (isa<EnumDecl>(DC)) DC = cast<EnumDecl>(DC)->getDeclContext();
+    if (isa<BlockDecl>(DC)) {
+      DC = cast<BlockDecl>(DC)->getDeclContext();
+      ++NumBlocks;
+    } else if (isa<EnumDecl>(DC))
+      DC = cast<EnumDecl>(DC)->getDeclContext();
     else break;
   }
 
-  // If we're not in an instance method, error out.
-  CXXMethodDecl *method = dyn_cast<CXXMethodDecl>(DC);
-  if (!method || !method->isInstance())
-    return 0;
+  QualType ThisTy;
+  if (CXXMethodDecl *method = dyn_cast<CXXMethodDecl>(DC)) {
+    if (method && method->isInstance())
+      ThisTy = method->getThisType(Context);
+  } else if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(DC)) {
+    // C++0x [expr.prim]p4:
+    //   Otherwise, if a member-declarator declares a non-static data member
+    // of a class X, the expression this is a prvalue of type "pointer to X"
+    // within the optional brace-or-equal-initializer.
+    Scope *S = getScopeForContext(DC);
+    if (!S || S->getFlags() & Scope::ThisScope)
+      ThisTy = Context.getPointerType(Context.getRecordType(RD));
+  }
 
-  // Mark that we're closing on 'this' in all the block scopes, if applicable.
-  for (unsigned idx = FunctionScopes.size() - 1;
-       isa<BlockScopeInfo>(FunctionScopes[idx]);
-       --idx)
-    cast<BlockScopeInfo>(FunctionScopes[idx])->CapturesCXXThis = true;
+  // Mark that we're closing on 'this' in all the block scopes we ignored.
+  if (!ThisTy.isNull())
+    for (unsigned idx = FunctionScopes.size() - 1;
+         NumBlocks; --idx, --NumBlocks)
+      cast<BlockScopeInfo>(FunctionScopes[idx])->CapturesCXXThis = true;
 
-  return method;
+  return ThisTy;
 }
 
-ExprResult Sema::ActOnCXXThis(SourceLocation loc) {
+ExprResult Sema::ActOnCXXThis(SourceLocation Loc) {
   /// C++ 9.3.2: In the body of a non-static member function, the keyword this
   /// is a non-lvalue expression whose value is the address of the object for
   /// which the function is called.
 
-  CXXMethodDecl *method = tryCaptureCXXThis();
-  if (!method) return Diag(loc, diag::err_invalid_this_use);
+  QualType ThisTy = getAndCaptureCurrentThisType();
+  if (ThisTy.isNull()) return Diag(Loc, diag::err_invalid_this_use);
 
-  return Owned(new (Context) CXXThisExpr(loc, method->getThisType(Context),
-                                         /*isImplicit=*/false));
+  return Owned(new (Context) CXXThisExpr(Loc, ThisTy, /*isImplicit=*/false));
 }
 
 ExprResult
@@ -2663,7 +2676,6 @@
         return true;
 
       bool FoundAssign = false;
-      bool AllNoThrow = true;
       DeclarationName Name = C.DeclarationNames.getCXXOperatorName(OO_Equal);
       LookupResult Res(Self, DeclarationNameInfo(Name, KeyLoc),
                        Sema::LookupOrdinaryName);
@@ -2675,15 +2687,15 @@
             FoundAssign = true;
             const FunctionProtoType *CPT
                 = Operator->getType()->getAs<FunctionProtoType>();
-            if (!CPT->isNothrow(Self.Context)) {
-              AllNoThrow = false;
-              break;
-            }
+            if (CPT->getExceptionSpecType() == EST_Delayed)
+              return false;
+            if (!CPT->isNothrow(Self.Context))
+              return false;
           }
         }
       }
 
-      return FoundAssign && AllNoThrow;
+      return FoundAssign;
     }
     return false;
   case UTT_HasNothrowCopy:
@@ -2700,7 +2712,6 @@
         return true;
 
       bool FoundConstructor = false;
-      bool AllNoThrow = true;
       unsigned FoundTQs;
       DeclContext::lookup_const_iterator Con, ConEnd;
       for (llvm::tie(Con, ConEnd) = Self.LookupConstructors(RD);
@@ -2715,16 +2726,16 @@
           FoundConstructor = true;
           const FunctionProtoType *CPT
               = Constructor->getType()->getAs<FunctionProtoType>();
+          if (CPT->getExceptionSpecType() == EST_Delayed)
+            return false;
           // FIXME: check whether evaluating default arguments can throw.
           // For now, we'll be conservative and assume that they can throw.
-          if (!CPT->isNothrow(Self.Context) || CPT->getNumArgs() > 1) {
-            AllNoThrow = false;
-            break;
-          }
+          if (!CPT->isNothrow(Self.Context) || CPT->getNumArgs() > 1)
+            return false;
         }
       }
 
-      return FoundConstructor && AllNoThrow;
+      return FoundConstructor;
     }
     return false;
   case UTT_HasNothrowConstructor:
@@ -2750,6 +2761,8 @@
         if (Constructor->isDefaultConstructor()) {
           const FunctionProtoType *CPT
               = Constructor->getType()->getAs<FunctionProtoType>();
+          if (CPT->getExceptionSpecType() == EST_Delayed)
+            return false;
           // TODO: check whether evaluating default arguments can throw.
           // For now, we'll be conservative and assume that they can throw.
           return CPT->isNothrow(Self.Context) && CPT->getNumArgs() == 0;
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index 444fb9a..3c19641 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -13,6 +13,7 @@
 #include "clang/Sema/SemaInternal.h"
 #include "TreeTransform.h"
 #include "clang/Sema/DeclSpec.h"
+#include "clang/Sema/Initialization.h"
 #include "clang/Sema/Lookup.h"
 #include "clang/Sema/Template.h"
 #include "clang/Sema/TemplateDeduction.h"
@@ -1744,6 +1745,8 @@
 
   TemplateDeclInstantiator Instantiator(*this, Instantiation, TemplateArgs);
   llvm::SmallVector<Decl*, 4> Fields;
+  llvm::SmallVector<std::pair<FieldDecl*, FieldDecl*>, 4>
+    FieldsWithMemberInitializers;
   for (RecordDecl::decl_iterator Member = Pattern->decls_begin(),
          MemberEnd = Pattern->decls_end();
        Member != MemberEnd; ++Member) {
@@ -1766,9 +1769,13 @@
 
     Decl *NewMember = Instantiator.Visit(*Member);
     if (NewMember) {
-      if (FieldDecl *Field = dyn_cast<FieldDecl>(NewMember))
+      if (FieldDecl *Field = dyn_cast<FieldDecl>(NewMember)) {
         Fields.push_back(Field);
-      else if (NewMember->isInvalidDecl())
+        FieldDecl *OldField = cast<FieldDecl>(*Member);
+        if (OldField->getInClassInitializer())
+          FieldsWithMemberInitializers.push_back(std::make_pair(OldField,
+                                                                Field));
+      } else if (NewMember->isInvalidDecl())
         Invalid = true;
     } else {
       // FIXME: Eventually, a NULL return will mean that one of the
@@ -1782,6 +1789,43 @@
               Fields.data(), Fields.size(), SourceLocation(), SourceLocation(),
               0);
   CheckCompletedCXXClass(Instantiation);
+
+  // Attach any in-class member initializers now the class is complete.
+  for (unsigned I = 0, N = FieldsWithMemberInitializers.size(); I != N; ++I) {
+    FieldDecl *OldField = FieldsWithMemberInitializers[I].first;
+    FieldDecl *NewField = FieldsWithMemberInitializers[I].second;
+    Expr *OldInit = OldField->getInClassInitializer();
+    ExprResult NewInit = SubstExpr(OldInit, TemplateArgs);
+
+    // If the initialization is no longer dependent, check it now.
+    if ((OldField->getType()->isDependentType() || OldInit->isTypeDependent())
+        && !NewField->getType()->isDependentType()
+        && !NewInit.get()->isTypeDependent()) {
+      // FIXME: handle list-initialization
+      SourceLocation EqualLoc = NewField->getLocation();
+      NewInit = PerformCopyInitialization(
+        InitializedEntity::InitializeMember(NewField), EqualLoc,
+        NewInit.release());
+
+      if (!NewInit.isInvalid()) {
+        CheckImplicitConversions(NewInit.get(), EqualLoc);
+
+        // C++0x [class.base.init]p7:
+        //   The initialization of each base and member constitutes a
+        //   full-expression.
+        NewInit = MaybeCreateExprWithCleanups(NewInit);
+      }
+    }
+
+    if (NewInit.isInvalid())
+      NewField->setInvalidDecl();
+    else
+      NewField->setInClassInitializer(NewInit.release());
+  }
+
+  if (!FieldsWithMemberInitializers.empty())
+    ActOnFinishDelayedMemberInitializers(Instantiation);
+
   if (Instantiation->isInvalidDecl())
     Invalid = true;
   else {
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 22db4c8..e78aa29 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -477,6 +477,7 @@
                                             D->getLocation(),
                                             D->isMutable(),
                                             BitWidth,
+                                            D->hasInClassInitializer(),
                                             D->getTypeSpecStartLoc(),
                                             D->getAccess(),
                                             0);
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index e7f9885..5fd8afa 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -1593,6 +1593,8 @@
       Error = 0; // Function prototype
       break;
     case Declarator::MemberContext:
+      if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static)
+        break;
       switch (cast<TagDecl>(CurContext)->getTagKind()) {
       case TTK_Enum: assert(0 && "unhandled tag kind"); break;
       case TTK_Struct: Error = 1; /* Struct member */ break;
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index 245499e..ff2e46a 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -6697,8 +6697,12 @@
 ExprResult
 TreeTransform<Derived>::TransformCXXThisExpr(CXXThisExpr *E) {
   DeclContext *DC = getSema().getFunctionLevelDeclContext();
-  CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(DC);
-  QualType T = MD->getThisType(getSema().Context);
+  QualType T;
+  if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(DC))
+    T = MD->getThisType(getSema().Context);
+  else
+    T = getSema().Context.getPointerType(
+      getSema().Context.getRecordType(cast<CXXRecordDecl>(DC)));
 
   if (!getDerived().AlwaysRebuild() && T == E->getType())
     return SemaRef.Owned(E);