Implement C++11 [expr.prim.general]p3, which permits the use of 'this'
in the declaration of a non-static member function after the
(optional) cv-qualifier-seq, which in practice means in the exception
specification and late-specified return type. 

The new scheme here used to manage 'this' outside of a member function
scope is more general than the Scope-based mechanism previously used
for non-static data member initializers and late-parsesd attributes,
because it can also handle the cv-qualifiers on the member
function. Note, however, that a separate pass is required for static
member functions to determine whether 'this' was used, because we
might not know that we have a static function until after declaration
matching.

Finally, this introduces name mangling for 'this' and for the implicit
'this', which is intended to match GCC's mangling. Independent
verification for the new mangling test case would be appreciated.

Fixes PR10036 and PR12450.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@154799 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index b6b6398..48c4872 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -3801,6 +3801,9 @@
 
 def err_invalid_this_use : Error<
   "invalid use of 'this' outside of a non-static member function">;
+def err_this_static_member_func : Error<
+  "'this' cannot be%select{| implicitly}0 used in a static member function "
+  "declaration">;
 def err_invalid_member_use_in_static_method : Error<
   "invalid use of member %0 in static member function">;
 def err_invalid_qualified_function_type : Error<
diff --git a/include/clang/Sema/Scope.h b/include/clang/Sema/Scope.h
index e9aa173..48f5417 100644
--- a/include/clang/Sema/Scope.h
+++ b/include/clang/Sema/Scope.h
@@ -81,13 +81,8 @@
     /// SwitchScope - This is a scope that corresponds to a switch statement.
     SwitchScope = 0x800,
 
-    /// ThisScope - This is the scope of a struct/union/class definition,
-    /// outside of any member function definition, where 'this' is nonetheless
-    /// usable.
-    ThisScope = 0x1000,
-    
     /// TryScope - This is the scope of a C++ try statement.
-    TryScope = 0x2000
+    TryScope = 0x1000
   };
 private:
   /// The parent scope for this scope.  This is null for the translation-unit
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index e8a9ff6..2427a75 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -446,11 +446,13 @@
     Sema &S;
     DeclContext *SavedContext;
     ProcessingContextState SavedContextState;
-
+    QualType SavedCXXThisTypeOverride;
+    
   public:
     ContextRAII(Sema &S, DeclContext *ContextToPush)
       : S(S), SavedContext(S.CurContext),
-        SavedContextState(S.DelayedDiagnostics.pushContext())
+        SavedContextState(S.DelayedDiagnostics.pushContext()),
+        SavedCXXThisTypeOverride(S.CXXThisTypeOverride)
     {
       assert(ContextToPush && "pushing null context");
       S.CurContext = ContextToPush;
@@ -460,6 +462,7 @@
       if (!SavedContext) return;
       S.CurContext = SavedContext;
       S.DelayedDiagnostics.popContext(SavedContextState);
+      S.CXXThisTypeOverride = SavedCXXThisTypeOverride;
       SavedContext = 0;
     }
 
@@ -646,7 +649,7 @@
 
   /// A stack of expression evaluation contexts.
   SmallVector<ExpressionEvaluationContextRecord, 8> ExprEvalContexts;
-
+  
   /// SpecialMemberOverloadResult - The overloading result for a special member
   /// function.
   ///
@@ -3247,6 +3250,18 @@
   /// special member function.
   bool isImplicitlyDeleted(FunctionDecl *FD);
   
+  /// \brief Check wither 'this' shows up in the type of a static member
+  /// function after the (naturally empty) cv-qualifier-seq would be.
+  ///
+  /// \returns true if an error occurred.
+  bool checkThisInStaticMemberFunctionType(CXXMethodDecl *Method);
+  
+  /// \brief Check wither 'this' shows up in the attributes of the given 
+  /// static member function.
+  ///
+  /// \returns true if an error occurred.
+  bool checkThisInStaticMemberFunctionAttributes(CXXMethodDecl *Method);
+  
   /// MaybeBindToTemporary - If the passed in expression has a record type with
   /// a non-trivial destructor, this will return CXXBindTemporaryExpr. Otherwise
   /// it simply returns the passed in expression.
@@ -3328,6 +3343,29 @@
   /// \returns The type of 'this', if possible. Otherwise, returns a NULL type.
   QualType getCurrentThisType();
 
+  /// \brief When non-NULL, the C++ 'this' expression is allowed despite the 
+  /// current context not being a non-static member function. In such cases,
+  /// this provides the type used for 'this'.
+  QualType CXXThisTypeOverride;
+  
+  /// \brief RAII object used to temporarily allow the C++ 'this' expression
+  /// to be used, with the given qualifiers on the current class type.
+  class CXXThisScopeRAII {
+    Sema &S;
+    QualType OldCXXThisTypeOverride;
+    bool Enabled;
+    
+  public:
+    /// \brief Introduce a new scope where 'this' may be allowed (when enabled),
+    /// using the given declaration (which is either a class template or a 
+    /// class) along with the given qualifiers.
+    /// along with the qualifiers placed on '*this'.
+    CXXThisScopeRAII(Sema &S, Decl *ContextDecl, unsigned CXXThisTypeQuals, 
+                     bool Enabled = true);
+    
+    ~CXXThisScopeRAII();
+  };
+  
   /// \brief Make sure the value of 'this' is actually available in the current
   /// context, if it is a potentially evaluated context.
   ///
@@ -3337,6 +3375,11 @@
   /// capture list.
   void CheckCXXThisCapture(SourceLocation Loc, bool Explicit = false);
 
+  /// \brief Determine whether the given type is the type of *this that is used
+  /// outside of the body of a member function for a type that is currently 
+  /// being defined.
+  bool isThisOutsideMemberFunctionBody(QualType BaseType);
+  
   /// ActOnCXXBoolLiteral - Parse {true,false} literals.
   ExprResult ActOnCXXBoolLiteral(SourceLocation OpLoc, tok::TokenKind Kind);
   
@@ -5481,7 +5524,9 @@
   TypeSourceInfo *SubstFunctionDeclType(TypeSourceInfo *T,
                             const MultiLevelTemplateArgumentList &TemplateArgs,
                                         SourceLocation Loc,
-                                        DeclarationName Entity);
+                                        DeclarationName Entity,
+                                        CXXRecordDecl *ThisContext,
+                                        unsigned ThisTypeQuals);
   ParmVarDecl *SubstParmVarDecl(ParmVarDecl *D,
                             const MultiLevelTemplateArgumentList &TemplateArgs,
                                 int indexAdjustment,
diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp
index d7b6354..0d405f1 100644
--- a/lib/AST/ItaniumMangle.cpp
+++ b/lib/AST/ItaniumMangle.cpp
@@ -2280,9 +2280,7 @@
 
 }
 
-/// Mangles a member expression.  Implicit accesses are not handled,
-/// but that should be okay, because you shouldn't be able to
-/// make an implicit access in a function template declaration.
+/// Mangles a member expression.
 void CXXNameMangler::mangleMemberExpr(const Expr *base,
                                       bool isArrow,
                                       NestedNameSpecifier *qualifier,
@@ -2291,8 +2289,17 @@
                                       unsigned arity) {
   // <expression> ::= dt <expression> <unresolved-name>
   //              ::= pt <expression> <unresolved-name>
-  Out << (isArrow ? "pt" : "dt");
-  mangleExpression(base);
+  if (base) {
+    if (base->isImplicitCXXThis()) {
+      // Note: GCC mangles member expressions to the implicit 'this' as
+      // *this., whereas we represent them as this->. The Itanium C++ ABI
+      // does not specify anything here, so we follow GCC.
+      Out << "dtdefpT";
+    } else {
+      Out << (isArrow ? "pt" : "dt");
+      mangleExpression(base);
+    }
+  }
   mangleUnresolvedName(qualifier, firstQualifierLookup, member, arity);
 }
 
@@ -2346,6 +2353,7 @@
   // <expr-primary> ::= L <type> <value number> E    # integer literal
   //                ::= L <type <value float> E      # floating literal
   //                ::= L <mangled-name> E           # external name
+  //                ::= fpT                          # 'this' expression
   QualType ImplicitlyConvertedToType;
   
 recurse:
@@ -2361,7 +2369,6 @@
   // These all can only appear in local or variable-initialization
   // contexts and so should never appear in a mangling.
   case Expr::AddrLabelExprClass:
-  case Expr::CXXThisExprClass:
   case Expr::DesignatedInitExprClass:
   case Expr::ImplicitValueInitExprClass:
   case Expr::ParenListExprClass:
@@ -2919,6 +2926,10 @@
     mangleExpression(cast<MaterializeTemporaryExpr>(E)->GetTemporaryExpr());
     break;
   }
+      
+  case Expr::CXXThisExprClass:
+    Out << "fpT";
+    break;
   }
 }
 
diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp
index 4bdded1..e50523a 100644
--- a/lib/AST/StmtProfile.cpp
+++ b/lib/AST/StmtProfile.cpp
@@ -763,6 +763,7 @@
 
 void StmtProfiler::VisitCXXThisExpr(const CXXThisExpr *S) {
   VisitExpr(S);
+  ID.AddBoolean(S->isImplicit());
 }
 
 void StmtProfiler::VisitCXXThrowExpr(const CXXThrowExpr *S) {
diff --git a/lib/Parse/ParseCXXInlineMethods.cpp b/lib/Parse/ParseCXXInlineMethods.cpp
index c000f69..d2a8535 100644
--- a/lib/Parse/ParseCXXInlineMethods.cpp
+++ b/lib/Parse/ParseCXXInlineMethods.cpp
@@ -447,9 +447,9 @@
   if (HasTemplateScope)
     Actions.ActOnReenterTemplateScope(getCurScope(), Class.TagOrTemplate);
 
-  // Set or update the scope flags to include Scope::ThisScope.
+  // Set or update the scope flags.
   bool AlreadyHasClassScope = Class.TopLevelClass;
-  unsigned ScopeFlags = Scope::ClassScope|Scope::DeclScope|Scope::ThisScope;
+  unsigned ScopeFlags = Scope::ClassScope|Scope::DeclScope;
   ParseScope ClassScope(this, ScopeFlags, !AlreadyHasClassScope);
   ParseScopeFlags ClassScopeFlags(this, ScopeFlags, AlreadyHasClassScope);
 
@@ -457,10 +457,20 @@
     Actions.ActOnStartDelayedMemberDeclarations(getCurScope(),
                                                 Class.TagOrTemplate);
 
-  for (size_t i = 0; i < Class.LateParsedDeclarations.size(); ++i) {
-    Class.LateParsedDeclarations[i]->ParseLexedMemberInitializers();
-  }
+  {
+    // C++11 [expr.prim.general]p4:
+    //   Otherwise, if a member-declarator declares a non-static data member 
+    //  (9.2) of a class X, the expression this is a prvalue of type "pointer
+    //  to X" within the optional brace-or-equal-initializer. It shall not 
+    //  appear elsewhere in the member-declarator.
+    Sema::CXXThisScopeRAII ThisScope(Actions, Class.TagOrTemplate,
+                                     /*TypeQuals=*/(unsigned)0);
 
+    for (size_t i = 0; i < Class.LateParsedDeclarations.size(); ++i) {
+      Class.LateParsedDeclarations[i]->ParseLexedMemberInitializers();
+    }
+  }
+  
   if (!AlreadyHasClassScope)
     Actions.ActOnFinishDelayedMemberDeclarations(getCurScope(),
                                                  Class.TagOrTemplate);
@@ -481,6 +491,7 @@
   ConsumeAnyToken();
 
   SourceLocation EqualLoc;
+    
   ExprResult Init = ParseCXXMemberInitializer(MI.Field, /*IsFunction=*/false, 
                                               EqualLoc);
 
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index 884820e..16c90e9 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -729,9 +729,9 @@
   if (HasTemplateScope)
     Actions.ActOnReenterTemplateScope(getCurScope(), Class.TagOrTemplate);
 
-  // Set or update the scope flags to include Scope::ThisScope.
+  // Set or update the scope flags.
   bool AlreadyHasClassScope = Class.TopLevelClass;
-  unsigned ScopeFlags = Scope::ClassScope|Scope::DeclScope|Scope::ThisScope;
+  unsigned ScopeFlags = Scope::ClassScope|Scope::DeclScope;
   ParseScope ClassScope(this, ScopeFlags, !AlreadyHasClassScope);
   ParseScopeFlags ClassScopeFlags(this, ScopeFlags, AlreadyHasClassScope);
 
@@ -739,11 +739,16 @@
   if (!AlreadyHasClassScope)
     Actions.ActOnStartDelayedMemberDeclarations(getCurScope(),
                                                 Class.TagOrTemplate);
-
-  for (unsigned i = 0, ni = Class.LateParsedDeclarations.size(); i < ni; ++i) {
-    Class.LateParsedDeclarations[i]->ParseLexedAttributes();
+  {
+    // Allow 'this' within late-parsed attributes.
+    Sema::CXXThisScopeRAII ThisScope(Actions, Class.TagOrTemplate, 
+                                     /*TypeQuals=*/0);
+    
+    for (unsigned i = 0, ni = Class.LateParsedDeclarations.size(); i < ni; ++i){
+      Class.LateParsedDeclarations[i]->ParseLexedAttributes();
+    }
   }
-
+  
   if (!AlreadyHasClassScope)
     Actions.ActOnFinishDelayedMemberDeclarations(getCurScope(),
                                                  Class.TagOrTemplate);
@@ -4242,6 +4247,23 @@
         EndLoc = RefQualifierLoc;
       }
 
+      // C++11 [expr.prim.general]p3:
+      //   If a declaration declares a member function or member function 
+      //   template of a class X, the expression this is a prvalue of type 
+      //   "pointer to cv-qualifier-seq X" between the optional cv-qualifer-seq
+      //   and the end of the function-definition, member-declarator, or 
+      //   declarator.
+      bool IsCXX11MemberFunction = 
+        getLangOpts().CPlusPlus0x &&
+        (D.getContext() == Declarator::MemberContext ||
+         (D.getContext() == Declarator::FileContext &&
+          D.getCXXScopeSpec().isValid() && 
+          Actions.CurContext->isRecord()));
+      Sema::CXXThisScopeRAII ThisScope(Actions,
+                               dyn_cast<CXXRecordDecl>(Actions.CurContext),
+                               DS.getTypeQualifiers(),
+                               IsCXX11MemberFunction);
+      
       // Parse exception-specification[opt].
       ESpecType = MaybeParseExceptionSpecification(ESpecRange,
                                                    DynamicExceptions,
diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp
index 491b4a1..ed96511 100644
--- a/lib/Parse/ParseExprCXX.cpp
+++ b/lib/Parse/ParseExprCXX.cpp
@@ -872,8 +872,6 @@
   // FIXME: Rename BlockScope -> ClosureScope if we decide to continue using
   // it.
   unsigned ScopeFlags = Scope::BlockScope | Scope::FnScope | Scope::DeclScope;
-  if (getCurScope()->getFlags() & Scope::ThisScope)
-    ScopeFlags |= Scope::ThisScope;
   ParseScope BodyScope(this, ScopeFlags);
 
   Actions.ActOnStartOfLambdaDefinition(Intro, D, getCurScope());
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp
index fcdfcac..30a9cd7 100644
--- a/lib/Sema/Sema.cpp
+++ b/lib/Sema/Sema.cpp
@@ -103,6 +103,7 @@
     AnalysisWarnings(*this)
 {
   TUScope = 0;
+  
   LoadedExternalKnownNamespaces = false;
   for (unsigned I = 0; I != NSAPI::NumNSNumberLiteralMethods; ++I)
     NSNumberLiteralMethods[I] = 0;
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 8b314b5..1d4745d 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -5834,6 +5834,9 @@
           }
         }
       }
+      
+      if (Method->isStatic())
+        checkThisInStaticMemberFunctionType(Method);
     }
 
     // Extra checking for C++ overloaded operators (C++ [over.oper]).
@@ -7554,7 +7557,11 @@
   // Always attach attributes to the underlying decl.
   if (TemplateDecl *TD = dyn_cast<TemplateDecl>(D))
     D = TD->getTemplatedDecl();
-  ProcessDeclAttributeList(S, D, Attrs.getList());
+  ProcessDeclAttributeList(S, D, Attrs.getList());  
+  
+  if (CXXMethodDecl *Method = dyn_cast_or_null<CXXMethodDecl>(D))
+    if (Method->isStatic())
+      checkThisInStaticMemberFunctionAttributes(Method);
 }
 
 
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 847f03c..f488296 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -25,6 +25,7 @@
 #include "clang/AST/DeclVisitor.h"
 #include "clang/AST/ExprCXX.h"
 #include "clang/AST/RecordLayout.h"
+#include "clang/AST/RecursiveASTVisitor.h"
 #include "clang/AST/StmtVisitor.h"
 #include "clang/AST/TypeLoc.h"
 #include "clang/AST/TypeOrdering.h"
@@ -11053,6 +11054,129 @@
     (*CI)->setInvalidDecl();
 }
 
+namespace {
+  /// \brief AST visitor that finds references to the 'this' expression.
+  class FindCXXThisExpr : public RecursiveASTVisitor<FindCXXThisExpr> {
+    Sema &S;
+    
+  public:
+    explicit FindCXXThisExpr(Sema &S) : S(S) { }
+    
+    bool VisitCXXThisExpr(CXXThisExpr *E) {
+      S.Diag(E->getLocation(), diag::err_this_static_member_func)
+        << E->isImplicit();
+      return false;
+    }
+  };
+}
+
+bool Sema::checkThisInStaticMemberFunctionType(CXXMethodDecl *Method) {
+  TypeSourceInfo *TSInfo = Method->getTypeSourceInfo();
+  if (!TSInfo)
+    return false;
+  
+  TypeLoc TL = TSInfo->getTypeLoc();
+  FunctionProtoTypeLoc *ProtoTL = dyn_cast<FunctionProtoTypeLoc>(&TL);
+  if (!ProtoTL)
+    return false;
+  
+  // C++11 [expr.prim.general]p3:
+  //   [The expression this] shall not appear before the optional 
+  //   cv-qualifier-seq and it shall not appear within the declaration of a 
+  //   static member function (although its type and value category are defined
+  //   within a static member function as they are within a non-static member
+  //   function). [ Note: this is because declaration matching does not occur
+  //  until the complete declarator is known. — end note ] 
+  const FunctionProtoType *Proto = ProtoTL->getTypePtr();
+  FindCXXThisExpr Finder(*this);
+  
+  // If the return type came after the cv-qualifier-seq, check it now.
+  if (Proto->hasTrailingReturn() &&
+      !Finder.TraverseTypeLoc(ProtoTL->getResultLoc()))
+    return true;
+
+  // Check the exception specification.
+  switch (Proto->getExceptionSpecType()) {
+  case EST_BasicNoexcept:
+  case EST_Delayed:
+  case EST_DynamicNone:
+  case EST_MSAny:
+  case EST_None:
+    break;
+
+  case EST_ComputedNoexcept:
+    if (!Finder.TraverseStmt(Proto->getNoexceptExpr()))
+      return true;
+      
+  case EST_Dynamic:
+    for (FunctionProtoType::exception_iterator E = Proto->exception_begin(),
+                                            EEnd = Proto->exception_end();
+         E != EEnd; ++E) {
+      if (!Finder.TraverseType(*E))
+        return true;
+    }
+    break;
+  }
+  
+  return checkThisInStaticMemberFunctionAttributes(Method);
+}
+
+bool Sema::checkThisInStaticMemberFunctionAttributes(CXXMethodDecl *Method) {
+  FindCXXThisExpr Finder(*this);
+
+  // Check attributes.
+  for (Decl::attr_iterator A = Method->attr_begin(), AEnd = Method->attr_end();
+       A != AEnd; ++A) {
+    // FIXME: This should be emitted by tblgen.
+    Expr *Arg = 0;
+    ArrayRef<Expr *> Args;
+    if (GuardedByAttr *G = dyn_cast<GuardedByAttr>(*A))
+      Arg = G->getArg();
+    else if (PtGuardedByAttr *G = dyn_cast<PtGuardedByAttr>(*A))
+      Arg = G->getArg();
+    else if (AcquiredAfterAttr *AA = dyn_cast<AcquiredAfterAttr>(*A))
+      Args = ArrayRef<Expr *>(AA->args_begin(), AA->args_size());
+    else if (AcquiredBeforeAttr *AB = dyn_cast<AcquiredBeforeAttr>(*A))
+      Args = ArrayRef<Expr *>(AB->args_begin(), AB->args_size());
+    else if (ExclusiveLockFunctionAttr *ELF 
+               = dyn_cast<ExclusiveLockFunctionAttr>(*A))
+      Args = ArrayRef<Expr *>(ELF->args_begin(), ELF->args_size());
+    else if (SharedLockFunctionAttr *SLF 
+               = dyn_cast<SharedLockFunctionAttr>(*A))
+      Args = ArrayRef<Expr *>(SLF->args_begin(), SLF->args_size());
+    else if (ExclusiveTrylockFunctionAttr *ETLF
+               = dyn_cast<ExclusiveTrylockFunctionAttr>(*A)) {
+      Arg = ETLF->getSuccessValue();
+      Args = ArrayRef<Expr *>(ETLF->args_begin(), ETLF->args_size());
+    } else if (SharedTrylockFunctionAttr *STLF
+                 = dyn_cast<SharedTrylockFunctionAttr>(*A)) {
+      Arg = STLF->getSuccessValue();
+      Args = ArrayRef<Expr *>(STLF->args_begin(), STLF->args_size());
+    } else if (UnlockFunctionAttr *UF = dyn_cast<UnlockFunctionAttr>(*A))
+      Args = ArrayRef<Expr *>(UF->args_begin(), UF->args_size());
+    else if (LockReturnedAttr *LR = dyn_cast<LockReturnedAttr>(*A))
+      Arg = LR->getArg();
+    else if (LocksExcludedAttr *LE = dyn_cast<LocksExcludedAttr>(*A))
+      Args = ArrayRef<Expr *>(LE->args_begin(), LE->args_size());
+    else if (ExclusiveLocksRequiredAttr *ELR 
+               = dyn_cast<ExclusiveLocksRequiredAttr>(*A))
+      Args = ArrayRef<Expr *>(ELR->args_begin(), ELR->args_size());
+    else if (SharedLocksRequiredAttr *SLR 
+               = dyn_cast<SharedLocksRequiredAttr>(*A))
+      Args = ArrayRef<Expr *>(SLR->args_begin(), SLR->args_size());
+
+    if (Arg && !Finder.TraverseStmt(Arg))
+      return true;
+    
+    for (unsigned I = 0, N = Args.size(); I != N; ++I) {
+      if (!Finder.TraverseStmt(Args[I]))
+        return true;
+    }
+  }
+  
+  return false;
+}
+
 /// IdentifyCUDATarget - Determine the CUDA compilation target for this function
 Sema::CUDAFunctionTarget Sema::IdentifyCUDATarget(const FunctionDecl *D) {
   // Implicitly declared functions (e.g. copy constructors) are
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index 31a8115..e4b40e6 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -654,23 +654,44 @@
 
 QualType Sema::getCurrentThisType() {
   DeclContext *DC = getFunctionLevelDeclContext();
-  QualType ThisTy;
+  QualType ThisTy = CXXThisTypeOverride;
   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));
   }
-
+  
   return ThisTy;
 }
 
+Sema::CXXThisScopeRAII::CXXThisScopeRAII(Sema &S, 
+                                         Decl *ContextDecl,
+                                         unsigned CXXThisTypeQuals,
+                                         bool Enabled) 
+  : S(S), OldCXXThisTypeOverride(S.CXXThisTypeOverride), Enabled(false)
+{
+  if (!Enabled || !ContextDecl)
+    return;
+  
+  CXXRecordDecl *Record = 0;
+  if (ClassTemplateDecl *Template = dyn_cast<ClassTemplateDecl>(ContextDecl))
+    Record = Template->getTemplatedDecl();
+  else
+    Record = cast<CXXRecordDecl>(ContextDecl);
+    
+  S.CXXThisTypeOverride
+    = S.Context.getPointerType(
+        S.Context.getRecordType(Record).withCVRQualifiers(CXXThisTypeQuals));
+  
+  this->Enabled = true;
+}
+
+
+Sema::CXXThisScopeRAII::~CXXThisScopeRAII() {
+  if (Enabled) {
+    S.CXXThisTypeOverride = OldCXXThisTypeOverride;
+  }
+}
+
 void Sema::CheckCXXThisCapture(SourceLocation Loc, bool Explicit) {
   // We don't need to capture this in an unevaluated context.
   if (ExprEvalContexts.back().Context == Unevaluated && !Explicit)
@@ -739,6 +760,18 @@
   return Owned(new (Context) CXXThisExpr(Loc, ThisTy, /*isImplicit=*/false));
 }
 
+bool Sema::isThisOutsideMemberFunctionBody(QualType BaseType) {
+  // If we're outside the body of a member function, then we'll have a specified
+  // type for 'this'.
+  if (CXXThisTypeOverride.isNull())
+    return false;
+  
+  // Determine whether we're looking into a class that's currently being
+  // defined.
+  CXXRecordDecl *Class = BaseType->getAsCXXRecordDecl();
+  return Class && Class->isBeingDefined();
+}
+
 ExprResult
 Sema::ActOnCXXTypeConstructExpr(ParsedType TypeRep,
                                 SourceLocation LParenLoc,
@@ -4784,8 +4817,13 @@
     return Owned(Base);
   }
 
-  // The object type must be complete (or dependent).
+  // The object type must be complete (or dependent), or
+  // C++11 [expr.prim.general]p3:
+  //   Unlike the object expression in other contexts, *this is not required to
+  //   be of complete type for purposes of class member access (5.2.5) outside 
+  //   the member function body.
   if (!BaseType->isDependentType() &&
+      !isThisOutsideMemberFunctionBody(BaseType) &&
       RequireCompleteType(OpLoc, BaseType,
                           PDiag(diag::err_incomplete_member_access)))
     return ExprError();
diff --git a/lib/Sema/SemaExprMember.cpp b/lib/Sema/SemaExprMember.cpp
index 26b88a2..6c84caa 100644
--- a/lib/Sema/SemaExprMember.cpp
+++ b/lib/Sema/SemaExprMember.cpp
@@ -101,16 +101,8 @@
 
   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;
+  bool isStaticContext = SemaRef.CXXThisTypeOverride.isNull() &&
+    (!isa<CXXMethodDecl>(DC) || cast<CXXMethodDecl>(DC)->isStatic());
 
   if (R.isUnresolvableResult())
     return isStaticContext ? IMA_Unresolved_StaticContext : IMA_Unresolved;
@@ -549,12 +541,13 @@
 }
 
 static bool
-LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
+LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R, 
                          SourceRange BaseRange, const RecordType *RTy,
                          SourceLocation OpLoc, CXXScopeSpec &SS,
                          bool HasTemplateArgs) {
   RecordDecl *RDecl = RTy->getDecl();
-  if (SemaRef.RequireCompleteType(OpLoc, QualType(RTy, 0),
+  if (!SemaRef.isThisOutsideMemberFunctionBody(QualType(RTy, 0)) &&
+      SemaRef.RequireCompleteType(OpLoc, QualType(RTy, 0),
                               SemaRef.PDiag(diag::err_typecheck_incomplete_tag)
                                     << BaseRange))
     return true;
diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp
index 2ea1e6f..d68e464 100644
--- a/lib/Sema/SemaTemplateDeduction.cpp
+++ b/lib/Sema/SemaTemplateDeduction.cpp
@@ -2310,23 +2310,42 @@
   // explicitly-specified template arguments. If the function has a trailing
   // return type, substitute it after the arguments to ensure we substitute
   // in lexical order.
-  if (Proto->hasTrailingReturn() &&
-      SubstParmTypes(Function->getLocation(),
-                     Function->param_begin(), Function->getNumParams(),
-                     MultiLevelTemplateArgumentList(*ExplicitArgumentList),
-                     ParamTypes))
-    return TDK_SubstitutionFailure;
-
+  if (Proto->hasTrailingReturn()) {
+    if (SubstParmTypes(Function->getLocation(),
+                       Function->param_begin(), Function->getNumParams(),
+                       MultiLevelTemplateArgumentList(*ExplicitArgumentList),
+                       ParamTypes))
+      return TDK_SubstitutionFailure;
+  }
+  
   // Instantiate the return type.
   // FIXME: exception-specifications?
-  QualType ResultType
-    = SubstType(Proto->getResultType(),
-                MultiLevelTemplateArgumentList(*ExplicitArgumentList),
-                Function->getTypeSpecStartLoc(),
-                Function->getDeclName());
-  if (ResultType.isNull() || Trap.hasErrorOccurred())
-    return TDK_SubstitutionFailure;
-
+  QualType ResultType;
+  {
+    // C++11 [expr.prim.general]p3:
+    //   If a declaration declares a member function or member function 
+    //   template of a class X, the expression this is a prvalue of type 
+    //   "pointer to cv-qualifier-seq X" between the optional cv-qualifer-seq
+    //   and the end of the function-definition, member-declarator, or 
+    //   declarator.
+    unsigned ThisTypeQuals = 0;
+    CXXRecordDecl *ThisContext = 0;
+    if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Function)) {
+      ThisContext = Method->getParent();
+      ThisTypeQuals = Method->getTypeQualifiers();
+    }
+      
+    CXXThisScopeRAII ThisScope(*this, ThisContext, ThisTypeQuals,
+                               getLangOpts().CPlusPlus0x);
+    
+    ResultType = SubstType(Proto->getResultType(),
+                   MultiLevelTemplateArgumentList(*ExplicitArgumentList),
+                   Function->getTypeSpecStartLoc(),
+                   Function->getDeclName());
+    if (ResultType.isNull() || Trap.hasErrorOccurred())
+      return TDK_SubstitutionFailure;
+  }
+  
   // Instantiate the types of each of the function parameters given the
   // explicitly-specified template arguments if we didn't do so earlier.
   if (!Proto->hasTrailingReturn() &&
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index 4740145..60de75b 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -789,6 +789,11 @@
     
     QualType TransformFunctionProtoType(TypeLocBuilder &TLB,
                                         FunctionProtoTypeLoc TL);
+    QualType TransformFunctionProtoType(TypeLocBuilder &TLB,
+                                        FunctionProtoTypeLoc TL,
+                                        CXXRecordDecl *ThisContext,
+                                        unsigned ThisTypeQuals);
+
     ParmVarDecl *TransformFunctionTypeParam(ParmVarDecl *OldParm,
                                             int indexAdjustment,
                                         llvm::Optional<unsigned> NumExpansions,
@@ -1211,6 +1216,16 @@
   return inherited::TransformFunctionProtoType(TLB, TL);
 }
 
+QualType TemplateInstantiator::TransformFunctionProtoType(TypeLocBuilder &TLB,
+                                 FunctionProtoTypeLoc TL,
+                                 CXXRecordDecl *ThisContext,
+                                 unsigned ThisTypeQuals) {
+  // We need a local instantiation scope for this function prototype.
+  LocalInstantiationScope Scope(SemaRef, /*CombineWithOuterScope=*/true);
+  return inherited::TransformFunctionProtoType(TLB, TL, ThisContext, 
+                                               ThisTypeQuals);  
+}
+
 ParmVarDecl *
 TemplateInstantiator::TransformFunctionTypeParam(ParmVarDecl *OldParm,
                                                  int indexAdjustment,
@@ -1446,7 +1461,9 @@
 TypeSourceInfo *Sema::SubstFunctionDeclType(TypeSourceInfo *T,
                                 const MultiLevelTemplateArgumentList &Args,
                                 SourceLocation Loc,
-                                DeclarationName Entity) {
+                                DeclarationName Entity,
+                                CXXRecordDecl *ThisContext,
+                                unsigned ThisTypeQuals) {
   assert(!ActiveTemplateInstantiations.empty() &&
          "Cannot perform an instantiation without some context on the "
          "instantiation stack");
@@ -1461,7 +1478,14 @@
   TypeLoc TL = T->getTypeLoc();
   TLB.reserve(TL.getFullDataSize());
 
-  QualType Result = Instantiator.TransformType(TLB, TL);
+  QualType Result;
+  
+  if (FunctionProtoTypeLoc *Proto = dyn_cast<FunctionProtoTypeLoc>(&TL)) {
+    Result = Instantiator.TransformFunctionProtoType(TLB, *Proto, ThisContext,
+                                                     ThisTypeQuals);
+  } else {
+    Result = Instantiator.TransformType(TLB, TL);
+  }
   if (Result.isNull())
     return 0;
 
@@ -1878,24 +1902,33 @@
   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();
+  {
+    // C++11 [expr.prim.general]p4:
+    //   Otherwise, if a member-declarator declares a non-static data member 
+    //  (9.2) of a class X, the expression this is a prvalue of type "pointer
+    //  to X" within the optional brace-or-equal-initializer. It shall not 
+    //  appear elsewhere in the member-declarator.
+    CXXThisScopeRAII ThisScope(*this, Instantiation, (unsigned)0);
+    
+    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 = SubstInitializer(OldInit, TemplateArgs,
-                                          /*CXXDirectInit=*/false);
-    if (NewInit.isInvalid())
-      NewField->setInvalidDecl();
-    else {
-      Expr *Init = NewInit.take();
-      assert(Init && "no-argument initializer in class");
-      assert(!isa<ParenListExpr>(Init) && "call-style init in class");
-      ActOnCXXInClassMemberInitializer(NewField,
-                                       Init->getSourceRange().getBegin(), Init);
+      ExprResult NewInit = SubstInitializer(OldInit, TemplateArgs,
+                                            /*CXXDirectInit=*/false);
+      if (NewInit.isInvalid())
+        NewField->setInvalidDecl();
+      else {
+        Expr *Init = NewInit.take();
+        assert(Init && "no-argument initializer in class");
+        assert(!isa<ParenListExpr>(Init) && "call-style init in class");
+        ActOnCXXInClassMemberInitializer(NewField, 
+                                         Init->getSourceRange().getBegin(), 
+                                         Init);
+      }
     }
   }
-
   // Instantiate late parsed attributes, and attach them to their decls.
   // See Sema::InstantiateAttrs
   for (LateInstantiatedAttrVec::iterator I = LateAttrs.begin(),
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 8afe7ac..8d382d1 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -2141,10 +2141,19 @@
   TypeSourceInfo *OldTInfo = D->getTypeSourceInfo();
   assert(OldTInfo && "substituting function without type source info");
   assert(Params.empty() && "parameter vector is non-empty at start");
+  
+  CXXRecordDecl *ThisContext = 0;
+  unsigned ThisTypeQuals = 0;
+  if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) {
+    ThisContext = Method->getParent();
+    ThisTypeQuals = Method->getTypeQualifiers();
+  }
+  
   TypeSourceInfo *NewTInfo
     = SemaRef.SubstFunctionDeclType(OldTInfo, TemplateArgs,
                                     D->getTypeSpecStartLoc(),
-                                    D->getDeclName());
+                                    D->getDeclName(),
+                                    ThisContext, ThisTypeQuals);
   if (!NewTInfo)
     return 0;
 
@@ -2243,6 +2252,22 @@
   assert(Proto && "Function template without prototype?");
 
   if (Proto->hasExceptionSpec() || Proto->getNoReturnAttr()) {
+    // C++11 [expr.prim.general]p3:
+    //   If a declaration declares a member function or member function 
+    //   template of a class X, the expression this is a prvalue of type 
+    //   "pointer to cv-qualifier-seq X" between the optional cv-qualifer-seq
+    //   and the end of the function-definition, member-declarator, or 
+    //   declarator.    
+    CXXRecordDecl *ThisContext = 0;
+    unsigned ThisTypeQuals = 0;
+    if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(New)) {
+      ThisContext = Method->getParent();
+      ThisTypeQuals = Method->getTypeQualifiers();
+    }
+    Sema::CXXThisScopeRAII ThisScope(SemaRef, ThisContext, ThisTypeQuals,
+                                     SemaRef.getLangOpts().CPlusPlus0x);
+    
+    
     // The function has an exception specification or a "noreturn"
     // attribute. Substitute into each of the exception types.
     SmallVector<QualType, 4> Exceptions;
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index acfea6e..5511fc0 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -522,6 +522,11 @@
   QualType Transform##CLASS##Type(TypeLocBuilder &TLB, CLASS##TypeLoc T);
 #include "clang/AST/TypeLocNodes.def"
 
+  QualType TransformFunctionProtoType(TypeLocBuilder &TLB,
+                                      FunctionProtoTypeLoc TL,
+                                      CXXRecordDecl *ThisContext,
+                                      unsigned ThisTypeQuals);
+
   StmtResult
   TransformSEHHandler(Stmt *Handler);
 
@@ -4165,6 +4170,15 @@
 QualType
 TreeTransform<Derived>::TransformFunctionProtoType(TypeLocBuilder &TLB,
                                                    FunctionProtoTypeLoc TL) {
+  return getDerived().TransformFunctionProtoType(TLB, TL, 0, 0);
+}
+
+template<typename Derived>
+QualType
+TreeTransform<Derived>::TransformFunctionProtoType(TypeLocBuilder &TLB,
+                                                   FunctionProtoTypeLoc TL,
+                                                   CXXRecordDecl *ThisContext,
+                                                   unsigned ThisTypeQuals) {
   // Transform the parameters and return type.
   //
   // We instantiate in source order, with the return type first followed by
@@ -4189,9 +4203,19 @@
                                                  ParamTypes, &ParamDecls))
       return QualType();
 
-    ResultType = getDerived().TransformType(TLB, TL.getResultLoc());
-    if (ResultType.isNull())
-      return QualType();
+    {
+      // C++11 [expr.prim.general]p3:
+      //   If a declaration declares a member function or member function 
+      //   template of a class X, the expression this is a prvalue of type 
+      //   "pointer to cv-qualifier-seq X" between the optional cv-qualifer-seq
+      //   and the end of the function-definition, member-declarator, or 
+      //   declarator.
+      Sema::CXXThisScopeRAII ThisScope(SemaRef, ThisContext, ThisTypeQuals);
+      
+      ResultType = getDerived().TransformType(TLB, TL.getResultLoc());
+      if (ResultType.isNull())
+        return QualType();
+    }
   }
   else {
     ResultType = getDerived().TransformType(TLB, TL.getResultLoc());
diff --git a/test/CXX/expr/expr.prim/expr.prim.general/p3-0x.cpp b/test/CXX/expr/expr.prim/expr.prim.general/p3-0x.cpp
new file mode 100644
index 0000000..f00e358
--- /dev/null
+++ b/test/CXX/expr/expr.prim/expr.prim.general/p3-0x.cpp
@@ -0,0 +1,90 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 %s -verify 
+
+struct A {
+  int &f(int*);
+  float &f(int*) const noexcept;
+  
+  int *ptr;
+  auto g1() noexcept(noexcept(f(ptr))) -> decltype(f(this->ptr));
+  auto g2() const noexcept(noexcept(f((*this).ptr))) -> decltype(f(ptr));
+};
+
+void testA(A &a) {
+  int &ir = a.g1();
+  float &fr = a.g2();
+  static_assert(!noexcept(a.g1()), "exception-specification failure");
+  static_assert(noexcept(a.g2()), "exception-specification failure");
+}
+
+struct B {
+  char g();
+  template<class T> auto f(T t) -> decltype(t + g())
+  { return t + g(); }
+};
+
+template auto B::f(int t) -> decltype(t + g());
+
+template<typename T>
+struct C {
+  int &f(T*);
+  float &f(T*) const noexcept;
+
+  T* ptr;
+  auto g1() noexcept(noexcept(f(ptr))) -> decltype(f((*this).ptr));
+  auto g2() const noexcept(noexcept(f(((this))->ptr))) -> decltype(f(ptr));
+};
+
+void test_C(C<int> ci) {
+  int *p = 0;
+  int &ir = ci.g1();
+  float &fr = ci.g2();
+  static_assert(!noexcept(ci.g1()), "exception-specification failure");
+  static_assert(noexcept(ci.g2()), "exception-specification failure");
+}
+
+namespace PR10036 {
+  template <class I>
+  void
+  iter_swap(I x, I y) noexcept;
+
+  template <class T>
+  class A
+  {
+    T t_;
+  public:
+    void swap(A& a) noexcept(noexcept(iter_swap(&t_, &a.t_)));
+  };
+
+  void test() {
+    A<int> i, j;
+    i.swap(j);
+  }
+}
+
+namespace Static {
+  struct X1 {
+    int m;
+    static auto f() -> decltype(m); // expected-error{{'this' cannot be implicitly used in a static member function declaration}}
+    static auto g() -> decltype(this->m); // expected-error{{'this' cannot be used in a static member function declaration}}
+
+    static int h();
+    
+    static int i() noexcept(noexcept(m + 2)); // expected-error{{'this' cannot be implicitly used in a static member function declaration}}
+  };
+
+  auto X1::h() -> decltype(m) { return 0; } // expected-error{{'this' cannot be implicitly used in a static member function declaration}}
+
+  template<typename T>
+  struct X2 {
+    int m;
+
+    T f(T*);
+    static T f(int);
+
+    auto g(T x) -> decltype(f(x)) { return 0; }
+  };
+
+  void test_X2() {
+    X2<int>().g(0);
+  }
+}
diff --git a/test/CodeGenCXX/mangle-this-cxx11.cpp b/test/CodeGenCXX/mangle-this-cxx11.cpp
new file mode 100644
index 0000000..f9e9479
--- /dev/null
+++ b/test/CodeGenCXX/mangle-this-cxx11.cpp
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -std=c++11 -emit-llvm %s -o - -triple=x86_64-apple-darwin9 | FileCheck %s
+
+struct B {
+ template <class U> U f();
+};
+
+struct A {
+ B b;
+ // implicitly rewritten to (*this).b.f<U>()
+ template <class U> auto f() -> decltype (b.f<U>());
+ template <class U> auto g() -> decltype (this->b.f<U>());
+};
+
+int main() {
+  A a;
+  // CHECK: call i32 @_ZN1A1fIiEEDTcldtdtdefpT1b1fIT_EEEv
+  a.f<int>();
+  // CHECK: call i32 @_ZN1A1gIiEEDTcldtptfpT1b1fIT_EEEv
+  a.g<int>();
+}
diff --git a/test/SemaCXX/warn-thread-safety-parsing.cpp b/test/SemaCXX/warn-thread-safety-parsing.cpp
index 587cb8a..c2fa1d7 100644
--- a/test/SemaCXX/warn-thread-safety-parsing.cpp
+++ b/test/SemaCXX/warn-thread-safety-parsing.cpp
@@ -1255,7 +1255,7 @@
   void foo4(FooLate *f) __attribute__((exclusive_locks_required(f->mu)));
 
   static void foo5()    __attribute__((exclusive_locks_required(mu))); // \
-    // expected-error {{invalid use of member 'mu' in static member function}}
+    // expected-error {{'this' cannot be implicitly used in a static member function declaration}}
 
   template <class T>
   void foo6() __attribute__((exclusive_locks_required(T::statmu))) { }