diff options
-rw-r--r-- | include/clang/Basic/DiagnosticSemaKinds.td | 3 | ||||
-rw-r--r-- | include/clang/Sema/Scope.h | 7 | ||||
-rw-r--r-- | include/clang/Sema/Sema.h | 53 | ||||
-rw-r--r-- | lib/AST/ItaniumMangle.cpp | 23 | ||||
-rw-r--r-- | lib/AST/StmtProfile.cpp | 1 | ||||
-rw-r--r-- | lib/Parse/ParseCXXInlineMethods.cpp | 21 | ||||
-rw-r--r-- | lib/Parse/ParseDecl.cpp | 34 | ||||
-rw-r--r-- | lib/Parse/ParseExprCXX.cpp | 2 | ||||
-rw-r--r-- | lib/Sema/Sema.cpp | 1 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 9 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 124 | ||||
-rw-r--r-- | lib/Sema/SemaExprCXX.cpp | 60 | ||||
-rw-r--r-- | lib/Sema/SemaExprMember.cpp | 17 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateDeduction.cpp | 49 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiate.cpp | 69 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiateDecl.cpp | 27 | ||||
-rw-r--r-- | lib/Sema/TreeTransform.h | 30 | ||||
-rw-r--r-- | test/CXX/expr/expr.prim/expr.prim.general/p3-0x.cpp | 90 | ||||
-rw-r--r-- | test/CodeGenCXX/mangle-this-cxx11.cpp | 20 | ||||
-rw-r--r-- | test/SemaCXX/warn-thread-safety-parsing.cpp | 2 |
20 files changed, 551 insertions, 91 deletions
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index b6b6398da9..48c48722f3 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -3801,6 +3801,9 @@ def warn_null_in_comparison_operation : Warning< 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 e9aa173cb9..48f54179ec 100644 --- a/include/clang/Sema/Scope.h +++ b/include/clang/Sema/Scope.h @@ -81,13 +81,8 @@ public: /// 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 e8a9ff6971..2427a757dc 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -446,11 +446,13 @@ public: 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 @@ public: if (!SavedContext) return; S.CurContext = SavedContext; S.DelayedDiagnostics.popContext(SavedContextState); + S.CXXThisTypeOverride = SavedCXXThisTypeOverride; SavedContext = 0; } @@ -646,7 +649,7 @@ public: /// A stack of expression evaluation contexts. SmallVector<ExpressionEvaluationContextRecord, 8> ExprEvalContexts; - + /// SpecialMemberOverloadResult - The overloading result for a special member /// function. /// @@ -3247,6 +3250,18 @@ public: /// 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 @@ public: /// \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 @@ public: /// 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 @@ public: 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 d7b6354540..0d405f1f57 100644 --- a/lib/AST/ItaniumMangle.cpp +++ b/lib/AST/ItaniumMangle.cpp @@ -2280,9 +2280,7 @@ void CXXNameMangler::mangleIntegerLiteral(QualType T, } -/// 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 @@ void CXXNameMangler::mangleMemberExpr(const Expr *base, 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 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) { // <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 @@ recurse: // 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 @@ recurse: 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 4bdded1d60..e50523ae86 100644 --- a/lib/AST/StmtProfile.cpp +++ b/lib/AST/StmtProfile.cpp @@ -763,6 +763,7 @@ void StmtProfiler::VisitCXXUuidofExpr(const CXXUuidofExpr *S) { 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 c000f69e6e..d2a85355b6 100644 --- a/lib/Parse/ParseCXXInlineMethods.cpp +++ b/lib/Parse/ParseCXXInlineMethods.cpp @@ -447,9 +447,9 @@ void Parser::ParseLexedMemberInitializers(ParsingClass &Class) { 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 @@ void Parser::ParseLexedMemberInitializers(ParsingClass &Class) { 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 @@ void Parser::ParseLexedMemberInitializer(LateParsedMemberInitializer &MI) { ConsumeAnyToken(); SourceLocation EqualLoc; + ExprResult Init = ParseCXXMemberInitializer(MI.Field, /*IsFunction=*/false, EqualLoc); diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 884820e023..16c90e9b71 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -729,9 +729,9 @@ void Parser::ParseLexedAttributes(ParsingClass &Class) { 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 @@ void Parser::ParseLexedAttributes(ParsingClass &Class) { 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 @@ void Parser::ParseFunctionDeclarator(Declarator &D, 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 491b4a1381..ed965115e3 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -872,8 +872,6 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( // 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 fcdfcace0c..30a9cd751a 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -103,6 +103,7 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, 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 8b314b524f..1d4745dcaa 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -5834,6 +5834,9 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, } } } + + if (Method->isStatic()) + checkThisInStaticMemberFunctionType(Method); } // Extra checking for C++ overloaded operators (C++ [over.oper]). @@ -7554,7 +7557,11 @@ void Sema::ActOnFinishDelayedAttribute(Scope *S, Decl *D, // 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 847f03c948..f488296336 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 @@ void Sema::CheckDelegatingCtorCycles() { (*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 31a8115f0b..e4b40e624c 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -654,23 +654,44 @@ ExprResult Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *E, 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 @@ ExprResult Sema::ActOnCXXThis(SourceLocation Loc) { 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 @@ Sema::ActOnStartCXXMemberReference(Scope *S, Expr *Base, SourceLocation OpLoc, 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 26b88a2a7e..6c84caa3f3 100644 --- a/lib/Sema/SemaExprMember.cpp +++ b/lib/Sema/SemaExprMember.cpp @@ -101,16 +101,8 @@ static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef, 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 @@ class RecordMemberExprValidatorCCC : public CorrectionCandidateCallback { } 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 2ea1e6ff93..d68e4642fc 100644 --- a/lib/Sema/SemaTemplateDeduction.cpp +++ b/lib/Sema/SemaTemplateDeduction.cpp @@ -2310,23 +2310,42 @@ Sema::SubstituteExplicitTemplateArguments( // 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 4740145fd5..60de75b917 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -789,6 +789,11 @@ namespace { 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 @@ QualType TemplateInstantiator::TransformFunctionProtoType(TypeLocBuilder &TLB, 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 @@ static bool NeedsInstantiationAsFunctionType(TypeSourceInfo *T) { 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 @@ TypeSourceInfo *Sema::SubstFunctionDeclType(TypeSourceInfo *T, TypeLoc TL = T->getTypeLoc(); TLB.reserve(TL.getFullDataSize()); - QualType Result = Instantiator.TransformType(TLB, TL); + QualType Result; + + if (Funct |