Index: cfe/trunk/include/clang/AST/Expr.h =================================================================== --- cfe/trunk/include/clang/AST/Expr.h +++ cfe/trunk/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 @@ 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; } Index: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td @@ -1100,6 +1100,9 @@ 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 @@ "%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">; Index: cfe/trunk/lib/Sema/SemaExpr.cpp =================================================================== --- cfe/trunk/lib/Sema/SemaExpr.cpp +++ cfe/trunk/lib/Sema/SemaExpr.cpp @@ -13241,7 +13241,8 @@ 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 @@ // 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; Index: cfe/trunk/lib/Sema/SemaOverload.cpp =================================================================== --- cfe/trunk/lib/Sema/SemaOverload.cpp +++ cfe/trunk/lib/Sema/SemaOverload.cpp @@ -11772,13 +11772,19 @@ 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); Index: cfe/trunk/test/SemaCXX/warn-pure-virtual-call-from-ctor-dtor.cpp =================================================================== --- cfe/trunk/test/SemaCXX/warn-pure-virtual-call-from-ctor-dtor.cpp +++ cfe/trunk/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 @@ 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(); + } +}; Index: cfe/trunk/test/SemaCXX/warn-pure-virtual-kext.cpp =================================================================== --- cfe/trunk/test/SemaCXX/warn-pure-virtual-kext.cpp +++ cfe/trunk/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}} + } +};