diff options
author | Aaron Ballman <aaron@aaronballman.com> | 2015-09-01 14:49:24 +0000 |
---|---|---|
committer | Aaron Ballman <aaron@aaronballman.com> | 2015-09-01 14:49:24 +0000 |
commit | 6924dcdf6f7370756098598020a0a53f5f248a3f (patch) | |
tree | 37f551623e96ec6428a905f3170381c43977ec66 /clang/lib/Sema/SemaExprMember.cpp | |
parent | c41355884258ad19fecfe2e1416863eaea62bb83 (diff) | |
download | bcm5719-llvm-6924dcdf6f7370756098598020a0a53f5f248a3f.tar.gz bcm5719-llvm-6924dcdf6f7370756098598020a0a53f5f248a3f.zip |
Add a new frontend warning for referencing members from the handler of a constructor or destructor function-try-block, which is UB in C++.
This corresponds to the CERT secure coding rule ERR53-CPP.
llvm-svn: 246548
Diffstat (limited to 'clang/lib/Sema/SemaExprMember.cpp')
-rw-r--r-- | clang/lib/Sema/SemaExprMember.cpp | 43 |
1 files changed, 35 insertions, 8 deletions
diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp index afeabf5d913..9c50605b82a 100644 --- a/clang/lib/Sema/SemaExprMember.cpp +++ b/clang/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); } |