From: Davide Italiano Date: Tue, 14 Jul 2015 23:36:10 +0000 (+0000) Subject: [Sema] Don't emit "pure virtual" warning for fully qualified calls. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=95deb3c575b20b3574a4658b377931ac27ea6d3e;p=clang [Sema] Don't emit "pure virtual" warning for fully qualified calls. -fapple-kext is an exception because calls will still go through the vtable in that mode. Add a note to make the user aware of that. PR: 23215 Differential Revision: http://reviews.llvm.org/D10935 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@242246 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h index 2a5b4c0f5e..0d1cf3a32e 100644 --- a/include/clang/AST/Expr.h +++ b/include/clang/AST/Expr.h @@ -23,6 +23,7 @@ #include "clang/AST/TemplateBase.h" #include "clang/AST/Type.h" #include "clang/Basic/CharInfo.h" +#include "clang/Basic/LangOptions.h" #include "clang/Basic/TypeTraits.h" #include "llvm/ADT/APFloat.h" #include "llvm/ADT/APSInt.h" @@ -2575,6 +2576,14 @@ public: HadMultipleCandidates = V; } + /// \brief Returns true if virtual dispatch is performed. + /// If the member access is fully qualified, (i.e. X::f()), virtual + /// dispatching is not performed. In -fapple-kext mode qualified + /// calls to virtual method will still go through the vtable. + bool performsVirtualDispatch(const LangOptions &LO) const { + return LO.AppleKext || !hasQualifier(); + } + static bool classof(const Stmt *T) { return T->getStmtClass() == MemberExprClass; } diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index fb1e3f1cb4..23e1714adb 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -1100,6 +1100,9 @@ def err_type_defined_in_alias_template : Error< def note_pure_virtual_function : Note< "unimplemented pure virtual method %0 in %1">; +def note_pure_qualified_call_kext : Note< + "qualified call to %0::%1 is treated as a virtual call to %1 due to -fapple-kext">; + def err_deleted_decl_not_first : Error< "deleted definition must be first declaration">; @@ -1312,8 +1315,9 @@ def err_qualified_member_of_unrelated : Error< "%q0 is not a member of class %1">; def warn_call_to_pure_virtual_member_function_from_ctor_dtor : Warning< - "call to pure virtual member function %0; overrides of %0 in subclasses are " - "not available in the %select{constructor|destructor}1 of %2">; + "call to pure virtual member function %0 has undefined behavior; " + "overrides of %0 in subclasses are not available in the " + "%select{constructor|destructor}1 of %2">; def note_member_declared_at : Note<"member is declared here">; def note_ivar_decl : Note<"instance variable is declared here">; diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 1ae983cad2..f384f56269 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -13241,7 +13241,8 @@ static void MarkExprReferenced(Sema &SemaRef, SourceLocation Loc, if (!MD) return; // Only attempt to devirtualize if this is truly a virtual call. - bool IsVirtualCall = MD->isVirtual() && !ME->hasQualifier(); + bool IsVirtualCall = MD->isVirtual() && + ME->performsVirtualDispatch(SemaRef.getLangOpts()); if (!IsVirtualCall) return; const Expr *Base = ME->getBase(); @@ -13275,7 +13276,7 @@ void Sema::MarkMemberReferenced(MemberExpr *E) { // expression, is odr-used, unless it is a pure virtual function and its // name is not explicitly qualified. bool OdrUse = true; - if (!E->hasQualifier()) { + if (E->performsVirtualDispatch(getLangOpts())) { if (CXXMethodDecl *Method = dyn_cast(E->getMemberDecl())) if (Method->isPure()) OdrUse = false; diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 31f581dc15..96107db520 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -11772,13 +11772,19 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, TheCall->getMethodDecl()->isPure()) { const CXXMethodDecl *MD = TheCall->getMethodDecl(); - if (isa(MemExpr->getBase()->IgnoreParenCasts())) { - Diag(MemExpr->getLocStart(), + if (isa(MemExpr->getBase()->IgnoreParenCasts()) && + MemExpr->performsVirtualDispatch(getLangOpts())) { + Diag(MemExpr->getLocStart(), diag::warn_call_to_pure_virtual_member_function_from_ctor_dtor) << MD->getDeclName() << isa(CurContext) << MD->getParent()->getDeclName(); Diag(MD->getLocStart(), diag::note_previous_decl) << MD->getDeclName(); + if (getLangOpts().AppleKext) + Diag(MemExpr->getLocStart(), + diag::note_pure_qualified_call_kext) + << MD->getParent()->getDeclName() + << MD->getDeclName(); } } return MaybeBindToTemporary(TheCall); diff --git a/test/SemaCXX/warn-pure-virtual-call-from-ctor-dtor.cpp b/test/SemaCXX/warn-pure-virtual-call-from-ctor-dtor.cpp index ade6198fbd..e69a81b77f 100644 --- a/test/SemaCXX/warn-pure-virtual-call-from-ctor-dtor.cpp +++ b/test/SemaCXX/warn-pure-virtual-call-from-ctor-dtor.cpp @@ -1,7 +1,7 @@ // RUN: %clang_cc1 %s -fsyntax-only -verify struct A { - A() { f(); } // expected-warning {{call to pure virtual member function 'f'; overrides of 'f' in subclasses are not available in the constructor of 'A'}} - ~A() { f(); } // expected-warning {{call to pure virtual member function 'f'; overrides of 'f' in subclasses are not available in the destructor of 'A'}} + A() { f(); } // expected-warning {{call to pure virtual member function 'f' has undefined behavior; overrides of 'f' in subclasses are not available in the constructor of 'A'}} + ~A() { f(); } // expected-warning {{call to pure virtual member function 'f' has undefined behavior; overrides of 'f' in subclasses are not available in the destructor of 'A'}} virtual void f() = 0; // expected-note 2 {{'f' declared here}} }; @@ -12,3 +12,11 @@ struct B { B() { a->f(); }; ~B() { a->f(); }; }; + +// Don't warn if the call is fully qualified. (PR23215) +struct C { + virtual void f() = 0; + C() { + C::f(); + } +}; diff --git a/test/SemaCXX/warn-pure-virtual-kext.cpp b/test/SemaCXX/warn-pure-virtual-kext.cpp new file mode 100644 index 0000000000..e681a02cc9 --- /dev/null +++ b/test/SemaCXX/warn-pure-virtual-kext.cpp @@ -0,0 +1,8 @@ +// RUN: %clang_cc1 %s -fapple-kext -fsyntax-only -verify + +struct A { + virtual void f() = 0; // expected-note {{'f' declared here}} + A() { + A::f(); // expected-warning {{call to pure virtual member function 'f' has undefined behavior; overrides of 'f' in subclasses are not available in the constructor of 'A'}} // expected-note {{qualified call to 'A'::'f' is treated as a virtual call to 'f' due to -fapple-kext}} + } +};