From 0e32c5283ae8307179da18ddeef112435bbcbf6b Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Fri, 25 Mar 2016 22:29:27 +0000 Subject: [PATCH] Don't warn on "use" of undefined inline function that isn't actually an ODR use. In order for this to fire, the function needed to be a templated function marked 'constexpr' and declared but not defined. This weird pattern appears in libstdc++'s alloc_traits.h. llvm-svn: 264471 --- clang/include/clang/Sema/Sema.h | 10 ++++++++-- clang/lib/Sema/SemaExpr.cpp | 31 ++++++++++++++++--------------- clang/test/SemaCXX/undefined-inline.cpp | 7 ++++++- 3 files changed, 30 insertions(+), 18 deletions(-) diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index cd7fe6c..9c48e0e 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -3593,9 +3593,15 @@ public: // for expressions referring to a decl; these exist because odr-use marking // needs to be delayed for some constant variables when we build one of the // named expressions. - void MarkAnyDeclReferenced(SourceLocation Loc, Decl *D, bool OdrUse); + // + // MightBeOdrUse indicates whether the use could possibly be an odr-use, and + // should usually be true. This only needs to be set to false if the lack of + // odr-use cannot be determined from the current context (for instance, + // because the name denotes a virtual function and was written without an + // explicit nested-name-specifier). + void MarkAnyDeclReferenced(SourceLocation Loc, Decl *D, bool MightBeOdrUse); void MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func, - bool OdrUse = true); + bool MightBeOdrUse = true); void MarkVariableReferenced(SourceLocation Loc, VarDecl *Var); void MarkDeclRefReferenced(DeclRefExpr *E); void MarkMemberReferenced(MemberExpr *E); diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 8b2ff75..b93a568 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -12770,7 +12770,7 @@ static bool IsPotentiallyEvaluatedContext(Sema &SemaRef) { /// \brief Mark a function referenced, and check whether it is odr-used /// (C++ [basic.def.odr]p2, C99 6.9p3) void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func, - bool OdrUse) { + bool MightBeOdrUse) { assert(Func && "No function?"); Func->setReferenced(); @@ -12783,8 +12783,8 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func, // We (incorrectly) mark overload resolution as an unevaluated context, so we // can just check that here. Skip the rest of this function if we've already // marked the function as used. - if (Func->isUsed(/*CheckUsedAttr=*/false) || - !IsPotentiallyEvaluatedContext(*this)) { + bool OdrUse = MightBeOdrUse && IsPotentiallyEvaluatedContext(*this); + if (Func->isUsed(/*CheckUsedAttr=*/false) || !OdrUse) { // C++11 [temp.inst]p3: // Unless a function template specialization has been explicitly // instantiated or explicitly specialized, the function template @@ -12873,8 +12873,6 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func, if (FPT && isUnresolvedExceptionSpec(FPT->getExceptionSpecType())) ResolveExceptionSpec(Loc, FPT); - if (!OdrUse) return; - // Implicit instantiation of function templates and member functions of // class templates. if (Func->isImplicitlyInstantiable()) { @@ -12922,10 +12920,12 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func, // Walk redefinitions, as some of them may be instantiable. for (auto i : Func->redecls()) { if (!i->isUsed(false) && i->isImplicitlyInstantiable()) - MarkFunctionReferenced(Loc, i); + MarkFunctionReferenced(Loc, i, OdrUse); } } + if (!OdrUse) return; + // Keep track of used but undefined functions. if (!Func->isDefined()) { if (mightHaveNonExternalLinkage(Func)) @@ -13800,13 +13800,13 @@ void Sema::MarkVariableReferenced(SourceLocation Loc, VarDecl *Var) { } static void MarkExprReferenced(Sema &SemaRef, SourceLocation Loc, - Decl *D, Expr *E, bool OdrUse) { + Decl *D, Expr *E, bool MightBeOdrUse) { if (VarDecl *Var = dyn_cast(D)) { DoMarkVarDeclReferenced(SemaRef, Loc, Var, E); return; } - SemaRef.MarkAnyDeclReferenced(Loc, D, OdrUse); + SemaRef.MarkAnyDeclReferenced(Loc, D, MightBeOdrUse); // If this is a call to a method via a cast, also mark the method in the // derived class used in case codegen can devirtualize the call. @@ -13828,7 +13828,7 @@ static void MarkExprReferenced(Sema &SemaRef, SourceLocation Loc, CXXMethodDecl *DM = MD->getCorrespondingMethodInClass(MostDerivedClassDecl); if (!DM || DM->isPure()) return; - SemaRef.MarkAnyDeclReferenced(Loc, DM, OdrUse); + SemaRef.MarkAnyDeclReferenced(Loc, DM, MightBeOdrUse); } /// \brief Perform reference-marking and odr-use handling for a DeclRefExpr. @@ -13851,30 +13851,31 @@ void Sema::MarkMemberReferenced(MemberExpr *E) { // overload resolution when referred to from a potentially-evaluated // expression, is odr-used, unless it is a pure virtual function and its // name is not explicitly qualified. - bool OdrUse = true; + bool MightBeOdrUse = true; if (E->performsVirtualDispatch(getLangOpts())) { if (CXXMethodDecl *Method = dyn_cast(E->getMemberDecl())) if (Method->isPure()) - OdrUse = false; + MightBeOdrUse = false; } SourceLocation Loc = E->getMemberLoc().isValid() ? E->getMemberLoc() : E->getLocStart(); - MarkExprReferenced(*this, Loc, E->getMemberDecl(), E, OdrUse); + MarkExprReferenced(*this, Loc, E->getMemberDecl(), E, MightBeOdrUse); } /// \brief Perform marking for a reference to an arbitrary declaration. It /// marks the declaration referenced, and performs odr-use checking for /// functions and variables. This method should not be used when building a /// normal expression which refers to a variable. -void Sema::MarkAnyDeclReferenced(SourceLocation Loc, Decl *D, bool OdrUse) { - if (OdrUse) { +void Sema::MarkAnyDeclReferenced(SourceLocation Loc, Decl *D, + bool MightBeOdrUse) { + if (MightBeOdrUse) { if (auto *VD = dyn_cast(D)) { MarkVariableReferenced(Loc, VD); return; } } if (auto *FD = dyn_cast(D)) { - MarkFunctionReferenced(Loc, FD, OdrUse); + MarkFunctionReferenced(Loc, FD, MightBeOdrUse); return; } D->setReferenced(); diff --git a/clang/test/SemaCXX/undefined-inline.cpp b/clang/test/SemaCXX/undefined-inline.cpp index 18973ef..feb12f4 100644 --- a/clang/test/SemaCXX/undefined-inline.cpp +++ b/clang/test/SemaCXX/undefined-inline.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsyntax-only -triple i686-pc-win32 -verify %s +// RUN: %clang_cc1 -fsyntax-only -triple i686-pc-win32 -verify -std=c++11 %s // PR14993 namespace test1 { @@ -61,3 +61,8 @@ namespace test11 { inline void bar() __attribute__((dllimport)); void test() { foo(); bar(); } } + +namespace test12 { + template constexpr int _S_chk(int *); + decltype(_S_chk(nullptr)) n; +} -- 2.7.4