diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 01fcc8714c4963eef67758e20489222f39109b2f..1e1ee9b6f5c1a0e8bed576615b806833e1f36c4c 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -5674,6 +5674,9 @@ def err_throw_incomplete_ptr : Error< "cannot throw pointer to object of incomplete type %0">; def err_return_in_constructor_handler : Error< "return in the catch of a function try block of a constructor is illegal">; +def warn_cdtor_function_try_handler_mem_expr : Warning< + "cannot refer to a non-static member from the handler of a " + "%select{constructor|destructor}0 function try block">, InGroup<Exceptions>; let CategoryName = "Lambda Issue" in { def err_capture_more_than_once : Error< diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index b66544c92801e689f8f5c1aea59cebbf4ba9e149..77cc667ab288b045a854231095d9793f59ac2ffc 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -3679,19 +3679,23 @@ public: ExprResult BuildPossibleImplicitMemberExpr(const CXXScopeSpec &SS, SourceLocation TemplateKWLoc, LookupResult &R, - const TemplateArgumentListInfo *TemplateArgs); + const TemplateArgumentListInfo *TemplateArgs, + const Scope *S); ExprResult BuildImplicitMemberExpr(const CXXScopeSpec &SS, SourceLocation TemplateKWLoc, LookupResult &R, const TemplateArgumentListInfo *TemplateArgs, - bool IsDefiniteInstance); + bool IsDefiniteInstance, + const Scope *S); bool UseArgumentDependentLookup(const CXXScopeSpec &SS, const LookupResult &R, bool HasTrailingLParen); - ExprResult BuildQualifiedDeclarationNameExpr( - CXXScopeSpec &SS, const DeclarationNameInfo &NameInfo, - bool IsAddressOfOperand, TypeSourceInfo **RecoveryTSI = nullptr); + ExprResult + BuildQualifiedDeclarationNameExpr(CXXScopeSpec &SS, + const DeclarationNameInfo &NameInfo, + bool IsAddressOfOperand, const Scope *S, + TypeSourceInfo **RecoveryTSI = nullptr); ExprResult BuildDependentDeclRefExpr(const CXXScopeSpec &SS, SourceLocation TemplateKWLoc, @@ -3808,6 +3812,7 @@ public: CXXScopeSpec &SS, SourceLocation TemplateKWLoc, NamedDecl *FirstQualifierInScope, const DeclarationNameInfo &NameInfo, const TemplateArgumentListInfo *TemplateArgs, + const Scope *S, ActOnMemberAccessExtraArgs *ExtraArgs = nullptr); ExprResult @@ -3816,6 +3821,7 @@ public: SourceLocation TemplateKWLoc, NamedDecl *FirstQualifierInScope, LookupResult &R, const TemplateArgumentListInfo *TemplateArgs, + const Scope *S, bool SuppressQualifierCheck = false, ActOnMemberAccessExtraArgs *ExtraArgs = nullptr); diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 72946e8fb82336cf5bd74055a16a1c49c6af26d8..b35b19d44a4c1cde66b3d253de53be1dd3d2520b 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -1022,7 +1022,7 @@ Corrected: if (FirstDecl->isCXXClassMember()) return BuildPossibleImplicitMemberExpr(SS, SourceLocation(), Result, - nullptr); + nullptr, S); bool ADL = UseArgumentDependentLookup(SS, Result, NextToken.is(tok::l_paren)); return BuildDeclarationNameExpr(SS, Result, ADL); diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 9c08495286c8fec72313898715de0ad85aadffaf..e80cde76e10cee375f36b3b0bc992c6c56e39e4b 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -3481,7 +3481,8 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor, /*TemplateKWLoc=*/SourceLocation(), /*FirstQualifierInScope=*/nullptr, MemberLookup, - /*TemplateArgs=*/nullptr); + /*TemplateArgs=*/nullptr, + /*S*/nullptr); if (CtorArg.isInvalid()) return true; @@ -9628,7 +9629,7 @@ public: Expr *build(Sema &S, SourceLocation Loc) const override { return assertNotNull(S.BuildMemberReferenceExpr( Builder.build(S, Loc), Type, Loc, IsArrow, SS, SourceLocation(), - nullptr, MemberLookup, nullptr).get()); + nullptr, MemberLookup, nullptr, nullptr).get()); } MemberBuilder(const ExprBuilder &Builder, QualType Type, bool IsArrow, @@ -9838,7 +9839,7 @@ buildSingleCopyAssignRecursively(Sema &S, SourceLocation Loc, QualType T, SS, /*TemplateKWLoc=*/SourceLocation(), /*FirstQualifierInScope=*/nullptr, OpLookup, - /*TemplateArgs=*/nullptr, + /*TemplateArgs=*/nullptr, /*S*/nullptr, /*SuppressQualifierCheck=*/true); if (OpEqualRef.isInvalid()) return StmtError(); diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 58e2d2db6f993938299592781658982c6c27da02..10b37557802de0bcafb2b1ee46d7dafbdf4abb78 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -2279,7 +2279,7 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS, if (MightBeImplicitMember) return BuildPossibleImplicitMemberExpr(SS, TemplateKWLoc, - R, TemplateArgs); + R, TemplateArgs, S); } if (TemplateArgs || TemplateKWLoc.isValid()) { @@ -2303,11 +2303,9 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS, /// declaration name, generally during template instantiation. /// There's a large number of things which don't need to be done along /// this path. -ExprResult -Sema::BuildQualifiedDeclarationNameExpr(CXXScopeSpec &SS, - const DeclarationNameInfo &NameInfo, - bool IsAddressOfOperand, - TypeSourceInfo **RecoveryTSI) { +ExprResult Sema::BuildQualifiedDeclarationNameExpr( + CXXScopeSpec &SS, const DeclarationNameInfo &NameInfo, + bool IsAddressOfOperand, const Scope *S, TypeSourceInfo **RecoveryTSI) { DeclContext *DC = computeDeclContext(SS, false); if (!DC) return BuildDependentDeclRefExpr(SS, /*TemplateKWLoc=*/SourceLocation(), @@ -2374,7 +2372,7 @@ Sema::BuildQualifiedDeclarationNameExpr(CXXScopeSpec &SS, if (!R.empty() && (*R.begin())->isCXXClassMember() && !IsAddressOfOperand) return BuildPossibleImplicitMemberExpr(SS, /*TemplateKWLoc=*/SourceLocation(), - R, /*TemplateArgs=*/nullptr); + R, /*TemplateArgs=*/nullptr, S); return BuildDeclarationNameExpr(SS, R, /* ADL */ false); } diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index f7103c885ad87625837fafca7795e1dd4175d790..a48e634c3cda1edaeea4c966d39c4e90e40788bf 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -6397,7 +6397,7 @@ static ExprResult attemptRecovery(Sema &SemaRef, if (MightBeImplicitMember) return SemaRef.BuildPossibleImplicitMemberExpr( NewSS, /*TemplateKWLoc*/ SourceLocation(), R, - /*TemplateArgs*/ nullptr); + /*TemplateArgs*/ nullptr, /*S*/ nullptr); } else if (auto *Ivar = dyn_cast<ObjCIvarDecl>(ND)) { return SemaRef.LookupInObjCMethod(R, Consumer.getScope(), Ivar->getIdentifier()); diff --git a/lib/Sema/SemaExprMember.cpp b/lib/Sema/SemaExprMember.cpp index afeabf5d913a9a5cb4de89b6437b87ff7f6d0034..9c50605b82a439431a38355d76116f4e5e53e227 100644 --- a/lib/Sema/SemaExprMember.cpp +++ b/lib/Sema/SemaExprMember.cpp @@ -234,15 +234,17 @@ ExprResult Sema::BuildPossibleImplicitMemberExpr(const CXXScopeSpec &SS, SourceLocation TemplateKWLoc, LookupResult &R, - const TemplateArgumentListInfo *TemplateArgs) { + const TemplateArgumentListInfo *TemplateArgs, + const Scope *S) { switch (ClassifyImplicitMemberAccess(*this, R)) { case IMA_Instance: - return BuildImplicitMemberExpr(SS, TemplateKWLoc, R, TemplateArgs, true); + return BuildImplicitMemberExpr(SS, TemplateKWLoc, R, TemplateArgs, true, S); case IMA_Mixed: case IMA_Mixed_Unrelated: case IMA_Unresolved: - return BuildImplicitMemberExpr(SS, TemplateKWLoc, R, TemplateArgs, false); + return BuildImplicitMemberExpr(SS, TemplateKWLoc, R, TemplateArgs, false, + S); case IMA_Field_Uneval_Context: Diag(R.getNameLoc(), diag::warn_cxx98_compat_non_static_member_use) @@ -656,7 +658,7 @@ static bool LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R, R.resolveKind(); return SemaRef.BuildMemberReferenceExpr( BaseExpr, BaseExpr->getType(), OpLoc, IsArrow, SS, SourceLocation(), - nullptr, R, nullptr); + nullptr, R, nullptr, nullptr); }, Sema::CTK_ErrorRecovery, DC); @@ -676,6 +678,7 @@ Sema::BuildMemberReferenceExpr(Expr *Base, QualType BaseType, NamedDecl *FirstQualifierInScope, const DeclarationNameInfo &NameInfo, const TemplateArgumentListInfo *TemplateArgs, + const Scope *S, ActOnMemberAccessExtraArgs *ExtraArgs) { if (BaseType->isDependentType() || (SS.isSet() && isDependentScopeSpecifier(SS))) @@ -722,7 +725,7 @@ Sema::BuildMemberReferenceExpr(Expr *Base, QualType BaseType, return BuildMemberReferenceExpr(Base, BaseType, OpLoc, IsArrow, SS, TemplateKWLoc, - FirstQualifierInScope, R, TemplateArgs, + FirstQualifierInScope, R, TemplateArgs, S, false, ExtraArgs); } @@ -874,6 +877,18 @@ static MemberExpr *BuildMemberExpr( return E; } +/// \brief Determine if the given scope is within a function-try-block handler. +static bool IsInFnTryBlockHandler(const Scope *S) { + // Walk the scope stack until finding a FnTryCatchScope, or leave the + // function scope. If a FnTryCatchScope is found, check whether the TryScope + // flag is set. If it is not, it's a function-try-block handler. + for (; S != S->getFnParent(); S = S->getParent()) { + if (S->getFlags() & Scope::FnTryCatchScope) + return (S->getFlags() & Scope::TryScope) != Scope::TryScope; + } + return false; +} + ExprResult Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType, SourceLocation OpLoc, bool IsArrow, @@ -882,6 +897,7 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType, NamedDecl *FirstQualifierInScope, LookupResult &R, const TemplateArgumentListInfo *TemplateArgs, + const Scope *S, bool SuppressQualifierCheck, ActOnMemberAccessExtraArgs *ExtraArgs) { QualType BaseType = BaseExprType; @@ -945,6 +961,17 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType, if (R.isAmbiguous()) return ExprError(); + // [except.handle]p10: Referring to any non-static member or base class of an + // object in the handler for a function-try-block of a constructor or + // destructor for that object results in undefined behavior. + const auto *FD = getCurFunctionDecl(); + if (S && BaseExpr && FD && + (isa<CXXDestructorDecl>(FD) || isa<CXXConstructorDecl>(FD)) && + isa<CXXThisExpr>(BaseExpr->IgnoreImpCasts()) && + IsInFnTryBlockHandler(S)) + Diag(MemberLoc, diag::warn_cdtor_function_try_handler_mem_expr) + << isa<CXXDestructorDecl>(FD); + if (R.empty()) { // Rederive where we looked up. DeclContext *DC = (SS.isSet() @@ -1634,7 +1661,7 @@ ExprResult Sema::ActOnMemberAccessExpr(Scope *S, Expr *Base, ActOnMemberAccessExtraArgs ExtraArgs = {S, Id, ObjCImpDecl}; return BuildMemberReferenceExpr(Base, Base->getType(), OpLoc, IsArrow, SS, TemplateKWLoc, FirstQualifierInScope, - NameInfo, TemplateArgs, &ExtraArgs); + NameInfo, TemplateArgs, S, &ExtraArgs); } static ExprResult @@ -1707,7 +1734,7 @@ Sema::BuildImplicitMemberExpr(const CXXScopeSpec &SS, SourceLocation TemplateKWLoc, LookupResult &R, const TemplateArgumentListInfo *TemplateArgs, - bool IsKnownInstance) { + bool IsKnownInstance, const Scope *S) { assert(!R.empty() && !R.isAmbiguous()); SourceLocation loc = R.getNameLoc(); @@ -1732,5 +1759,5 @@ Sema::BuildImplicitMemberExpr(const CXXScopeSpec &SS, /*IsArrow*/ true, SS, TemplateKWLoc, /*FirstQualifierInScope*/ nullptr, - R, TemplateArgs); + R, TemplateArgs, S); } diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 2e52d3003943ca694f398238f479509cc33a033d..251873542f347e7d65b71ad110234b03af2437ab 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -10701,8 +10701,8 @@ BuildRecoveryCallExpr(Sema &SemaRef, Scope *S, Expr *Fn, // casts and such from the call, we don't really care. ExprResult NewFn = ExprError(); if ((*R.begin())->isCXXClassMember()) - NewFn = SemaRef.BuildPossibleImplicitMemberExpr(SS, TemplateKWLoc, - R, ExplicitTemplateArgs); + NewFn = SemaRef.BuildPossibleImplicitMemberExpr(SS, TemplateKWLoc, R, + ExplicitTemplateArgs, S); else if (ExplicitTemplateArgs || TemplateKWLoc.isValid()) NewFn = SemaRef.BuildTemplateIdExpr(SS, TemplateKWLoc, R, false, ExplicitTemplateArgs); @@ -12321,7 +12321,7 @@ Sema::BuildForRangeBeginEndCall(Scope *S, SourceLocation Loc, /*TemplateKWLoc=*/SourceLocation(), /*FirstQualifierInScope=*/nullptr, MemberLookup, - /*TemplateArgs=*/nullptr); + /*TemplateArgs=*/nullptr, S); if (MemberRef.isInvalid()) { *CallExpr = ExprError(); Diag(Range->getLocStart(), diag::note_in_for_range) diff --git a/lib/Sema/SemaStmtAsm.cpp b/lib/Sema/SemaStmtAsm.cpp index 9f944abb49aca74bd3d12249b368009b476bd10b..b148cc9c7614774b541eb67e31d29a849a35e15b 100644 --- a/lib/Sema/SemaStmtAsm.cpp +++ b/lib/Sema/SemaStmtAsm.cpp @@ -675,7 +675,7 @@ Sema::LookupInlineAsmVarDeclField(Expr *E, StringRef Member, unsigned &Offset, // Make an Expr to thread through OpDecl. ExprResult Result = BuildMemberReferenceExpr( E, E->getType(), AsmLoc, /*IsArrow=*/false, CXXScopeSpec(), - SourceLocation(), nullptr, FieldResult, nullptr); + SourceLocation(), nullptr, FieldResult, nullptr, nullptr); if (Result.isInvalid()) return Result; Info.OpDecl = Result.get(); diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index 799127e50be1ccd029743110f340cf01f9d82753..9074c39ad5db9eaca66f8ea3d9da211bd0b47458 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -1968,7 +1968,8 @@ public: return getSema().BuildMemberReferenceExpr(Base, BaseType, OpLoc, isArrow, SS, TemplateKWLoc, FirstQualifierInScope, - R, ExplicitTemplateArgs); + R, ExplicitTemplateArgs, + /*S*/nullptr); } /// \brief Build a new binary operator expression. @@ -2034,7 +2035,8 @@ public: SS, SourceLocation(), /*FirstQualifierInScope*/ nullptr, NameInfo, - /* TemplateArgs */ nullptr); + /* TemplateArgs */ nullptr, + /*S*/ nullptr); } /// \brief Build a new initializer list expression. @@ -2482,7 +2484,7 @@ public: TemplateArgs); return getSema().BuildQualifiedDeclarationNameExpr( - SS, NameInfo, IsAddressOfOperand, RecoveryTSI); + SS, NameInfo, IsAddressOfOperand, /*S*/nullptr, RecoveryTSI); } /// \brief Build a new template-id expression. @@ -2576,7 +2578,7 @@ public: SS, TemplateKWLoc, FirstQualifierInScope, MemberNameInfo, - TemplateArgs); + TemplateArgs, /*S*/nullptr); } /// \brief Build a new member reference expression. @@ -2598,7 +2600,7 @@ public: OperatorLoc, IsArrow, SS, TemplateKWLoc, FirstQualifierInScope, - R, TemplateArgs); + R, TemplateArgs, /*S*/nullptr); } /// \brief Build a new noexcept expression. @@ -2738,7 +2740,8 @@ public: SS, SourceLocation(), /*FirstQualifierInScope=*/nullptr, NameInfo, - /*TemplateArgs=*/nullptr); + /*TemplateArgs=*/nullptr, + /*S=*/nullptr); } /// \brief Build a new Objective-C property reference expression. @@ -2756,7 +2759,8 @@ public: SS, SourceLocation(), /*FirstQualifierInScope=*/nullptr, NameInfo, - /*TemplateArgs=*/nullptr); + /*TemplateArgs=*/nullptr, + /*S=*/nullptr); } /// \brief Build a new Objective-C property reference expression. @@ -2788,7 +2792,8 @@ public: SS, SourceLocation(), /*FirstQualifierInScope=*/nullptr, NameInfo, - /*TemplateArgs=*/nullptr); + /*TemplateArgs=*/nullptr, + /*S=*/nullptr); } /// \brief Build a new shuffle vector expression. @@ -11186,7 +11191,8 @@ TreeTransform<Derived>::RebuildCXXPseudoDestructorExpr(Expr *Base, SS, TemplateKWLoc, /*FIXME: FirstQualifier*/ nullptr, NameInfo, - /*TemplateArgs*/ nullptr); + /*TemplateArgs*/ nullptr, + /*S*/nullptr); } template<typename Derived> diff --git a/test/SemaCXX/cdtor-fn-try-block.cpp b/test/SemaCXX/cdtor-fn-try-block.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9e903ec74293b8cd83fea6d0d914fdf600c885cd --- /dev/null +++ b/test/SemaCXX/cdtor-fn-try-block.cpp @@ -0,0 +1,97 @@ +// RUN: %clang_cc1 -fsyntax-only -fcxx-exceptions -verify %s -std=c++14 + +int FileScope; + +struct A { + int I; + void f(); + A() try { + } catch (...) { + I = 12; // expected-warning {{cannot refer to a non-static member from the handler of a constructor function try block}} + f(); // expected-warning {{cannot refer to a non-static member from the handler of a constructor function try block}} + + FileScope = 12; // ok + A a; + a.I = 12; // ok + } +}; + +struct B { + int I; + void f(); +}; + +struct C : B { + C() try { + } catch (...) { + I = 12; // expected-warning {{cannot refer to a non-static member from the handler of a constructor function try block}} + f(); // expected-warning {{cannot refer to a non-static member from the handler of a constructor function try block}} + } +}; + +struct D { + static int I; + static void f(); + + D() try { + } catch (...) { + I = 12; // ok + f(); // ok + } +}; +int D::I; + +struct E { + int I; + void f(); + static int J; + static void g(); + + ~E() try { + } catch (...) { + I = 12; // expected-warning {{cannot refer to a non-static member from the handler of a destructor function try block}} + f(); // expected-warning {{cannot refer to a non-static member from the handler of a destructor function try block}} + + J = 12; // ok + g(); // ok + } +}; +int E::J; + +struct F { + static int I; + static void f(); +}; +int F::I; + +struct G : F { + G() try { + } catch (...) { + I = 12; // ok + f(); // ok + } +}; + +struct H { + struct A {}; + enum { + E + }; + + H() try { + } catch (...) { + H::A a; // ok + int I = E; // ok + } +}; + +struct I { + int J; + + I() { + try { // not a function-try-block + } catch (...) { + J = 12; // ok + } + } +}; \ No newline at end of file diff --git a/test/SemaObjCXX/delay-parsing-func-tryblock.mm b/test/SemaObjCXX/delay-parsing-func-tryblock.mm index ecee7be629c342686434f08f85d8659195f28e6a..f6b849b955836c180d35812043d36566d008d48f 100644 --- a/test/SemaObjCXX/delay-parsing-func-tryblock.mm +++ b/test/SemaObjCXX/delay-parsing-func-tryblock.mm @@ -1,5 +1,4 @@ // RUN: %clang_cc1 -x objective-c++ -fcxx-exceptions -fsyntax-only -Werror -verify -Wno-objc-root-class %s -// expected-no-diagnostics // rdar://10387088 @interface MyClass @@ -29,13 +28,13 @@ BadReturn::BadReturn(MyClass * myObject) try : CObj(myObject) { try { [myObject privateMethod]; [myObject privateMethod1]; - getMe = bar(myObject); - [CObj privateMethod1]; + getMe = bar(myObject); // expected-error {{cannot refer to a non-static member from the handler of a constructor function try block}} + [CObj privateMethod1]; // expected-error {{cannot refer to a non-static member from the handler of a constructor function try block}} } catch(int ei) { - i = ei; + i = ei; // expected-error {{cannot refer to a non-static member from the handler of a constructor function try block}} } catch(...) { { - i = 0; + i = 0; // expected-error {{cannot refer to a non-static member from the handler of a constructor function try block}} } } }