From: Reid Kleckner Date: Tue, 16 Sep 2014 22:23:33 +0000 (+0000) Subject: Don't try to devirtualize non-virtual calls X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=d575b2f55a27e17e966bc1b969d2b5c117ba425c;p=clang Don't try to devirtualize non-virtual calls We would end up marking the vtable of the derived class as used for no reason. Because the call itself is qualified, it is never virtual, and the vtable of the derived class isn't helpful. We would end up rejecting code that MSVC accepts for no benefit. See http://crbug.com/413478 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@217910 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 57c4f33ca0..6b01b1f4b0 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -12581,6 +12581,10 @@ static void MarkExprReferenced(Sema &SemaRef, SourceLocation Loc, CXXMethodDecl *MD = dyn_cast(ME->getMemberDecl()); if (!MD) return; + // Only attempt to devirtualize if this is truly a virtual call. + bool IsVirtualCall = MD->isVirtual() && !ME->hasQualifier(); + if (!IsVirtualCall) + return; const Expr *Base = ME->getBase(); const CXXRecordDecl *MostDerivedClassDecl = Base->getBestDynamicClassType(); if (!MostDerivedClassDecl) diff --git a/test/SemaCXX/devirtualize-vtable-marking.cpp b/test/SemaCXX/devirtualize-vtable-marking.cpp new file mode 100644 index 0000000000..fc3e8ce770 --- /dev/null +++ b/test/SemaCXX/devirtualize-vtable-marking.cpp @@ -0,0 +1,47 @@ +// RUN: %clang_cc1 -verify -std=c++11 %s + +template struct OwnPtr { + T *p; + ~OwnPtr() { + // expected-error@+1 {{invalid application of 'sizeof'}} + static_assert(sizeof(T) > 0, "incomplete T"); + delete p; + } +}; + +namespace use_vtable_for_vcall { +struct Incomplete; // expected-note {{forward declaration}} +struct A { + virtual ~A() {} + virtual void m() {} +}; +struct B : A { // expected-note {{in instantiation}} + B(); + virtual void m() { } + virtual void m2() { static_cast(this)->m(); } + OwnPtr m_sqlError; +}; + +B *f() { + return new B(); +} +} + +namespace dont_mark_qualified_vcall { +struct Incomplete; +struct A { + virtual ~A() {} + virtual void m() {} +}; +struct B : A { + B(); + // Previously we would mark B's vtable referenced to devirtualize this call to + // A::m, even though it's not a virtual call. + virtual void m() { A::m(); } + OwnPtr m_sqlError; +}; + +B *f() { + return new B(); +} +}