From d575b2f55a27e17e966bc1b969d2b5c117ba425c Mon Sep 17 00:00:00 2001 From: Reid Kleckner Date: Tue, 16 Sep 2014 22:23:33 +0000 Subject: [PATCH] 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 --- lib/Sema/SemaExpr.cpp | 4 ++ test/SemaCXX/devirtualize-vtable-marking.cpp | 47 ++++++++++++++++++++ 2 files changed, 51 insertions(+) create mode 100644 test/SemaCXX/devirtualize-vtable-marking.cpp 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(); +} +} -- 2.50.1