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 (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 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, 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 = 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); + { + // 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); + } } } - // 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 8afe7aca97..8d382d1bac 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -2141,10 +2141,19 @@ TemplateDeclInstantiator::SubstFunctionType(FunctionDecl *D, 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 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New, 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 acfea6e3e4..5511fc00f5 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -522,6 +522,11 @@ public: 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 @@ template<typename Derived> 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 @@ TreeTransform<Derived>::TransformFunctionProtoType(TypeLocBuilder &TLB, 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 0000000000..f00e358f3a --- /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 0000000000..f9e94797b1 --- /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 587cb8a4c7..c2fa1d77a0 100644 --- a/test/SemaCXX/warn-thread-safety-parsing.cpp +++ b/test/SemaCXX/warn-thread-safety-parsing.cpp @@ -1255,7 +1255,7 @@ public: 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))) { } |