From: Reid Kleckner Date: Fri, 23 Jun 2017 18:29:13 +0000 (+0000) Subject: [MS] Don't statically initialize dllimport member function pointers X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=20e77878ed5d88eb9bcf88ee34e6fab4459cb92a;p=clang [MS] Don't statically initialize dllimport member function pointers We were already applying the same rules to dllimport function pointers. David Majnemer added that logic back in r211677 to fix PR20130. We failed to extend that logic to non-virtual member function pointers, which are basically function pointers in a struct with some extra offsets. Fixes PR33570. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@306137 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index 768947d00a..60f8143c13 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -1665,6 +1665,19 @@ static bool CheckLValueConstantExpression(EvalInfo &Info, SourceLocation Loc, return true; } +/// Member pointers are constant expressions unless they point to a +/// non-virtual dllimport member function. +static bool CheckMemberPointerConstantExpression(EvalInfo &Info, + SourceLocation Loc, + QualType Type, + const APValue &Value) { + const ValueDecl *Member = Value.getMemberPointerDecl(); + const auto *FD = dyn_cast_or_null(Member); + if (!FD) + return true; + return FD->isVirtual() || !FD->hasAttr(); +} + /// Check that this core constant expression is of literal type, and if not, /// produce an appropriate diagnostic. static bool CheckLiteralType(EvalInfo &Info, const Expr *E, @@ -1757,6 +1770,9 @@ static bool CheckConstantExpression(EvalInfo &Info, SourceLocation DiagLoc, return CheckLValueConstantExpression(Info, DiagLoc, Type, LVal); } + if (Value.isMemberPointer()) + return CheckMemberPointerConstantExpression(Info, DiagLoc, Type, Value); + // Everything else is fine. return true; } diff --git a/test/CodeGenCXX/dllimport-memptr-global.cpp b/test/CodeGenCXX/dllimport-memptr-global.cpp new file mode 100644 index 0000000000..e64537b8b9 --- /dev/null +++ b/test/CodeGenCXX/dllimport-memptr-global.cpp @@ -0,0 +1,58 @@ +// Also check that -Wglobal-constructors does the right thing. Strictly +// speaking, this is a Sema test, but this avoids test case duplication. +// RUN: %clang_cc1 -Wglobal-constructors %s -verify -triple i686-windows-msvc -fms-extensions -std=c++11 +// +// RUN: %clang_cc1 %s -emit-llvm -o - -triple i686-windows-msvc -fms-extensions -std=c++11 | FileCheck %s + +struct __declspec(dllimport) Single { + void nonvirt(); + virtual void virt(); +}; + +struct A { int a; }; +struct B { int b; }; +struct __declspec(dllimport) Multi : A, B { + void nonvirt(); + virtual void virt(); +}; + +struct __declspec(dllimport) Virtual : virtual A { + void nonvirt(); + virtual void virt(); +}; + +struct General; +static_assert(sizeof(void (General::*)()) == 16, "force general memptr model"); +struct __declspec(dllimport) General { + void nonvirt(); + virtual void virt(); +}; + +auto mp_single_nv = &Single::nonvirt; // expected-warning {{global constructor}} +auto mp_multi_nv = &Multi::nonvirt; // expected-warning {{global constructor}} +auto mp_virtual_nv = &Virtual::nonvirt; // expected-warning {{global constructor}} +auto mp_general_nv = &General::nonvirt; // expected-warning {{global constructor}} + +auto mp_single_v = &Single::virt; +auto mp_multi_v = &Multi::virt; +auto mp_virtual_v = &Virtual::virt; +auto mp_general_v = &General::virt; + +// All of the non-virtual globals need dynamic initializers. + +// CHECK: @"\01?mp_single_nv@@3P8Single@@AEXXZQ1@" = global i8* null, align 4 +// CHECK: @"\01?mp_multi_nv@@3P8Multi@@AEXXZQ1@" = global { i8*, i32 } zeroinitializer, align 4 +// CHECK: @"\01?mp_virtual_nv@@3P8Virtual@@AEXXZQ1@" = global { i8*, i32, i32 } zeroinitializer, align 4 +// CHECK: @"\01?mp_general_nv@@3P8General@@AEXXZQ1@" = global { i8*, i32, i32, i32 } zeroinitializer, align 4 + +// CHECK: @"\01?mp_single_v@@3P8Single@@AEXXZQ1@" = global i8* bitcast (void (%struct.Single*, ...)* @"\01??_9Single@@$BA@AE" to i8*), align 4 +// CHECK: @"\01?mp_multi_v@@3P8Multi@@AEXXZQ1@" = global { i8*, i32 } { i8* bitcast (void (%struct.Multi*, ...)* @"\01??_9Multi@@$BA@AE" to i8*), i32 0 }, align 4 +// CHECK: @"\01?mp_virtual_v@@3P8Virtual@@AEXXZQ1@" = global { i8*, i32, i32 } { i8* bitcast (void (%struct.Virtual*, ...)* @"\01??_9Virtual@@$BA@AE" to i8*), i32 0, i32 0 }, align 4 +// CHECK: @"\01?mp_general_v@@3P8General@@AEXXZQ1@" = global { i8*, i32, i32, i32 } { i8* bitcast (void (%struct.General*, ...)* @"\01??_9General@@$BA@AE" to i8*), i32 0, i32 0, i32 0 }, align 4 + +// CHECK: define internal void @_GLOBAL__sub_I{{.*}}() {{.*}} { +// CHECK: call void @"\01??__Emp_single_nv@@YAXXZ"() +// CHECK: call void @"\01??__Emp_multi_nv@@YAXXZ"() +// CHECK: call void @"\01??__Emp_virtual_nv@@YAXXZ"() +// CHECK: call void @"\01??__Emp_general_nv@@YAXXZ"() +// CHECK: }