diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index c1bfb962677add..e6afe7a5b42126 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// #include "TreeTransform.h" +#include "UsedDeclVisitor.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ASTLambda.h" @@ -17400,71 +17401,33 @@ void Sema::MarkDeclarationsReferencedInType(SourceLocation Loc, QualType T) { } namespace { - /// Helper class that marks all of the declarations referenced by - /// potentially-evaluated subexpressions as "referenced". - class EvaluatedExprMarker : public EvaluatedExprVisitor { - Sema &S; - bool SkipLocalVariables; - - public: - typedef EvaluatedExprVisitor Inherited; - - EvaluatedExprMarker(Sema &S, bool SkipLocalVariables) - : Inherited(S.Context), S(S), SkipLocalVariables(SkipLocalVariables) { } - - void VisitDeclRefExpr(DeclRefExpr *E) { - // If we were asked not to visit local variables, don't. - if (SkipLocalVariables) { - if (VarDecl *VD = dyn_cast(E->getDecl())) - if (VD->hasLocalStorage()) - return; - } - - S.MarkDeclRefReferenced(E); - } - - void VisitMemberExpr(MemberExpr *E) { - S.MarkMemberReferenced(E); - Inherited::VisitMemberExpr(E); - } - - void VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E) { - S.MarkFunctionReferenced( - E->getBeginLoc(), - const_cast(E->getTemporary()->getDestructor())); - Visit(E->getSubExpr()); - } +/// Helper class that marks all of the declarations referenced by +/// potentially-evaluated subexpressions as "referenced". +class EvaluatedExprMarker : public UsedDeclVisitor { +public: + typedef UsedDeclVisitor Inherited; + bool SkipLocalVariables; - void VisitCXXNewExpr(CXXNewExpr *E) { - if (E->getOperatorNew()) - S.MarkFunctionReferenced(E->getBeginLoc(), E->getOperatorNew()); - if (E->getOperatorDelete()) - S.MarkFunctionReferenced(E->getBeginLoc(), E->getOperatorDelete()); - Inherited::VisitCXXNewExpr(E); - } + EvaluatedExprMarker(Sema &S, bool SkipLocalVariables) + : Inherited(S), SkipLocalVariables(SkipLocalVariables) {} - void VisitCXXDeleteExpr(CXXDeleteExpr *E) { - if (E->getOperatorDelete()) - S.MarkFunctionReferenced(E->getBeginLoc(), E->getOperatorDelete()); - QualType Destroyed = S.Context.getBaseElementType(E->getDestroyedType()); - if (const RecordType *DestroyedRec = Destroyed->getAs()) { - CXXRecordDecl *Record = cast(DestroyedRec->getDecl()); - S.MarkFunctionReferenced(E->getBeginLoc(), S.LookupDestructor(Record)); - } - - Inherited::VisitCXXDeleteExpr(E); - } + void visitUsedDecl(SourceLocation Loc, Decl *D) { + S.MarkFunctionReferenced(Loc, cast(D)); + } - void VisitCXXConstructExpr(CXXConstructExpr *E) { - S.MarkFunctionReferenced(E->getBeginLoc(), E->getConstructor()); - Inherited::VisitCXXConstructExpr(E); + void VisitDeclRefExpr(DeclRefExpr *E) { + // If we were asked not to visit local variables, don't. + if (SkipLocalVariables) { + if (VarDecl *VD = dyn_cast(E->getDecl())) + if (VD->hasLocalStorage()) + return; } + S.MarkDeclRefReferenced(E); + } - void VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E) { - Visit(E->getExpr()); - } - }; -} + void VisitMemberExpr(MemberExpr *E) { S.MarkMemberReferenced(E); } +}; +} // namespace /// Mark any declarations that appear within this expression or any /// potentially-evaluated subexpressions as "referenced". diff --git a/clang/lib/Sema/UsedDeclVisitor.h b/clang/lib/Sema/UsedDeclVisitor.h new file mode 100644 index 00000000000000..be46f0d4affcca --- /dev/null +++ b/clang/lib/Sema/UsedDeclVisitor.h @@ -0,0 +1,90 @@ +//===- UsedDeclVisitor.h - ODR-used declarations visitor --------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +//===----------------------------------------------------------------------===// +// +// This file defines UsedDeclVisitor, a CRTP class which visits all the +// declarations that are ODR-used by an expression or statement. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_SEMA_USEDDECLVISITOR_H +#define LLVM_CLANG_LIB_SEMA_USEDDECLVISITOR_H + +#include "clang/AST/EvaluatedExprVisitor.h" +#include "clang/Sema/SemaInternal.h" + +namespace clang { +template +class UsedDeclVisitor : public EvaluatedExprVisitor { +protected: + Sema &S; + +public: + typedef EvaluatedExprVisitor Inherited; + + UsedDeclVisitor(Sema &S) : Inherited(S.Context), S(S) {} + + Derived &asImpl() { return *static_cast(this); } + + void VisitDeclRefExpr(DeclRefExpr *E) { + auto *D = E->getDecl(); + if (isa(D) || isa(D)) { + asImpl().visitUsedDecl(E->getLocation(), D); + } + } + + void VisitMemberExpr(MemberExpr *E) { + auto *D = E->getMemberDecl(); + if (isa(D) || isa(D)) { + asImpl().visitUsedDecl(E->getMemberLoc(), D); + } + asImpl().Visit(E->getBase()); + } + + void VisitCapturedStmt(CapturedStmt *Node) { + asImpl().visitUsedDecl(Node->getBeginLoc(), Node->getCapturedDecl()); + Inherited::VisitCapturedStmt(Node); + } + + void VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E) { + asImpl().visitUsedDecl( + E->getBeginLoc(), + const_cast(E->getTemporary()->getDestructor())); + asImpl().Visit(E->getSubExpr()); + } + + void VisitCXXNewExpr(CXXNewExpr *E) { + if (E->getOperatorNew()) + asImpl().visitUsedDecl(E->getBeginLoc(), E->getOperatorNew()); + if (E->getOperatorDelete()) + asImpl().visitUsedDecl(E->getBeginLoc(), E->getOperatorDelete()); + Inherited::VisitCXXNewExpr(E); + } + + void VisitCXXDeleteExpr(CXXDeleteExpr *E) { + if (E->getOperatorDelete()) + asImpl().visitUsedDecl(E->getBeginLoc(), E->getOperatorDelete()); + QualType Destroyed = S.Context.getBaseElementType(E->getDestroyedType()); + if (const RecordType *DestroyedRec = Destroyed->getAs()) { + CXXRecordDecl *Record = cast(DestroyedRec->getDecl()); + asImpl().visitUsedDecl(E->getBeginLoc(), S.LookupDestructor(Record)); + } + + Inherited::VisitCXXDeleteExpr(E); + } + + void VisitCXXConstructExpr(CXXConstructExpr *E) { + asImpl().visitUsedDecl(E->getBeginLoc(), E->getConstructor()); + Inherited::VisitCXXConstructExpr(E); + } + + void VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E) { + asImpl().Visit(E->getExpr()); + } +}; +} // end namespace clang + +#endif // LLVM_CLANG_LIB_SEMA_USEDDECLVISITOR_H