aaron.ballman updated this revision to Diff 33078.
aaron.ballman added a comment.
This patch completely reworks the way the warning is implemented by moving it
into the frontend instead of clang-tidy.
http://reviews.llvm.org/D12301
Files:
include/clang/Basic/DiagnosticSemaKinds.td
include/clang/Sema/Sema.h
lib/Sema/SemaDecl.cpp
lib/Sema/SemaDeclCXX.cpp
lib/Sema/SemaExpr.cpp
lib/Sema/SemaExprCXX.cpp
lib/Sema/SemaExprMember.cpp
lib/Sema/SemaOverload.cpp
lib/Sema/TreeTransform.h
test/SemaCXX/cdtor-fn-try-block.cpp
Index: test/SemaCXX/cdtor-fn-try-block.cpp
===================================================================
--- test/SemaCXX/cdtor-fn-try-block.cpp
+++ 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
Index: lib/Sema/TreeTransform.h
===================================================================
--- lib/Sema/TreeTransform.h
+++ lib/Sema/TreeTransform.h
@@ -1955,7 +1955,8 @@
return getSema().BuildMemberReferenceExpr(Base, BaseType, OpLoc, isArrow,
SS, TemplateKWLoc,
FirstQualifierInScope,
- R, ExplicitTemplateArgs);
+ R, ExplicitTemplateArgs,
+ /*S*/nullptr);
}
/// \brief Build a new binary operator expression.
@@ -2021,7 +2022,8 @@
SS, SourceLocation(),
/*FirstQualifierInScope*/ nullptr,
NameInfo,
- /* TemplateArgs */ nullptr);
+ /* TemplateArgs */ nullptr,
+ /*S*/ nullptr);
}
/// \brief Build a new initializer list expression.
@@ -2469,7 +2471,7 @@
TemplateArgs);
return getSema().BuildQualifiedDeclarationNameExpr(
- SS, NameInfo, IsAddressOfOperand, RecoveryTSI);
+ SS, NameInfo, IsAddressOfOperand, /*S*/nullptr, RecoveryTSI);
}
/// \brief Build a new template-id expression.
@@ -2563,7 +2565,7 @@
SS, TemplateKWLoc,
FirstQualifierInScope,
MemberNameInfo,
- TemplateArgs);
+ TemplateArgs, /*S*/nullptr);
}
/// \brief Build a new member reference expression.
@@ -2585,7 +2587,7 @@
OperatorLoc, IsArrow,
SS, TemplateKWLoc,
FirstQualifierInScope,
- R, TemplateArgs);
+ R, TemplateArgs, /*S*/nullptr);
}
/// \brief Build a new noexcept expression.
@@ -2725,7 +2727,8 @@
SS, SourceLocation(),
/*FirstQualifierInScope=*/nullptr,
NameInfo,
- /*TemplateArgs=*/nullptr);
+ /*TemplateArgs=*/nullptr,
+ /*S=*/nullptr);
}
/// \brief Build a new Objective-C property reference expression.
@@ -2743,7 +2746,8 @@
SS, SourceLocation(),
/*FirstQualifierInScope=*/nullptr,
NameInfo,
- /*TemplateArgs=*/nullptr);
+ /*TemplateArgs=*/nullptr,
+ /*S=*/nullptr);
}
/// \brief Build a new Objective-C property reference expression.
@@ -2775,7 +2779,8 @@
SS, SourceLocation(),
/*FirstQualifierInScope=*/nullptr,
NameInfo,
- /*TemplateArgs=*/nullptr);
+ /*TemplateArgs=*/nullptr,
+ /*S=*/nullptr);
}
/// \brief Build a new shuffle vector expression.
@@ -11143,7 +11148,8 @@
SS, TemplateKWLoc,
/*FIXME: FirstQualifier*/ nullptr,
NameInfo,
- /*TemplateArgs*/ nullptr);
+ /*TemplateArgs*/ nullptr,
+ /*S*/nullptr);
}
template<typename Derived>
Index: lib/Sema/SemaOverload.cpp
===================================================================
--- lib/Sema/SemaOverload.cpp
+++ lib/Sema/SemaOverload.cpp
@@ -10678,8 +10678,8 @@
// 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);
@@ -12288,7 +12288,7 @@
/*TemplateKWLoc=*/SourceLocation(),
/*FirstQualifierInScope=*/nullptr,
MemberLookup,
- /*TemplateArgs=*/nullptr);
+ /*TemplateArgs=*/nullptr, S);
if (MemberRef.isInvalid()) {
*CallExpr = ExprError();
Diag(Range->getLocStart(), diag::note_in_for_range)
Index: lib/Sema/SemaExprMember.cpp
===================================================================
--- lib/Sema/SemaExprMember.cpp
+++ lib/Sema/SemaExprMember.cpp
@@ -234,15 +234,17 @@
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 @@
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 @@
NamedDecl *FirstQualifierInScope,
const DeclarationNameInfo &NameInfo,
const TemplateArgumentListInfo *TemplateArgs,
+ const Scope *S,
ActOnMemberAccessExtraArgs *ExtraArgs) {
if (BaseType->isDependentType() ||
(SS.isSet() && isDependentScopeSpecifier(SS)))
@@ -722,7 +725,7 @@
return BuildMemberReferenceExpr(Base, BaseType,
OpLoc, IsArrow, SS, TemplateKWLoc,
- FirstQualifierInScope, R, TemplateArgs,
+ FirstQualifierInScope, R, TemplateArgs, S,
false, ExtraArgs);
}
@@ -874,6 +877,19 @@
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.
+ do {
+ if (S->getFlags() & Scope::FnTryCatchScope)
+ return (S->getFlags() & Scope::TryScope) != Scope::TryScope;
+ S = S->getParent();
+ } while (S != S->getFnParent());
+ return false;
+}
+
ExprResult
Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
SourceLocation OpLoc, bool IsArrow,
@@ -882,6 +898,7 @@
NamedDecl *FirstQualifierInScope,
LookupResult &R,
const TemplateArgumentListInfo *TemplateArgs,
+ const Scope *S,
bool SuppressQualifierCheck,
ActOnMemberAccessExtraArgs *ExtraArgs) {
QualType BaseType = BaseExprType;
@@ -945,6 +962,19 @@
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.
+ if (S && BaseExpr && isa<CXXThisExpr>(BaseExpr->IgnoreImpCasts()) &&
+ IsInFnTryBlockHandler(S)) {
+ const auto *FD = getCurFunctionDecl();
+ bool IsDestructor = isa<CXXDestructorDecl>(FD);
+ if (IsDestructor || isa<CXXConstructorDecl>(FD)) {
+ Diag(MemberLoc, diag::warn_cdtor_function_try_handler_mem_expr)
+ << IsDestructor;
+ }
+ }
+
if (R.empty()) {
// Rederive where we looked up.
DeclContext *DC = (SS.isSet()
@@ -1634,7 +1664,7 @@
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 +1737,7 @@
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 +1762,5 @@
/*IsArrow*/ true,
SS, TemplateKWLoc,
/*FirstQualifierInScope*/ nullptr,
- R, TemplateArgs);
+ R, TemplateArgs, S);
}
Index: lib/Sema/SemaExprCXX.cpp
===================================================================
--- lib/Sema/SemaExprCXX.cpp
+++ lib/Sema/SemaExprCXX.cpp
@@ -6397,7 +6397,7 @@
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());
Index: lib/Sema/SemaExpr.cpp
===================================================================
--- lib/Sema/SemaExpr.cpp
+++ lib/Sema/SemaExpr.cpp
@@ -2278,7 +2278,7 @@
if (MightBeImplicitMember)
return BuildPossibleImplicitMemberExpr(SS, TemplateKWLoc,
- R, TemplateArgs);
+ R, TemplateArgs, S);
}
if (TemplateArgs || TemplateKWLoc.isValid()) {
@@ -2302,11 +2302,9 @@
/// 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(),
@@ -2373,7 +2371,7 @@
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);
}
Index: lib/Sema/SemaDeclCXX.cpp
===================================================================
--- lib/Sema/SemaDeclCXX.cpp
+++ lib/Sema/SemaDeclCXX.cpp
@@ -3481,7 +3481,8 @@
/*TemplateKWLoc=*/SourceLocation(),
/*FirstQualifierInScope=*/nullptr,
MemberLookup,
- /*TemplateArgs=*/nullptr);
+ /*TemplateArgs=*/nullptr,
+ /*S*/nullptr);
if (CtorArg.isInvalid())
return true;
@@ -9628,7 +9629,7 @@
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 @@
SS, /*TemplateKWLoc=*/SourceLocation(),
/*FirstQualifierInScope=*/nullptr,
OpLookup,
- /*TemplateArgs=*/nullptr,
+ /*TemplateArgs=*/nullptr, /*S*/nullptr,
/*SuppressQualifierCheck=*/true);
if (OpEqualRef.isInvalid())
return StmtError();
Index: lib/Sema/SemaDecl.cpp
===================================================================
--- lib/Sema/SemaDecl.cpp
+++ lib/Sema/SemaDecl.cpp
@@ -1022,7 +1022,7 @@
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);
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -3675,19 +3675,23 @@
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,
@@ -3801,6 +3805,7 @@
CXXScopeSpec &SS, SourceLocation TemplateKWLoc,
NamedDecl *FirstQualifierInScope, const DeclarationNameInfo &NameInfo,
const TemplateArgumentListInfo *TemplateArgs,
+ const Scope *S,
ActOnMemberAccessExtraArgs *ExtraArgs = nullptr);
ExprResult
@@ -3809,6 +3814,7 @@
SourceLocation TemplateKWLoc,
NamedDecl *FirstQualifierInScope, LookupResult &R,
const TemplateArgumentListInfo *TemplateArgs,
+ const Scope *S,
bool SuppressQualifierCheck = false,
ActOnMemberAccessExtraArgs *ExtraArgs = nullptr);
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -5672,6 +5672,9 @@
"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<
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits