summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorReid Kleckner <rnk@google.com>2017-06-23 18:29:13 +0000
committerReid Kleckner <rnk@google.com>2017-06-23 18:29:13 +0000
commit9c980cb50211431a1e8fc58639199389b0440f52 (patch)
tree6f2a9e578fbab5684e07c5aa150803ba72d2c140
parent5a7eca5223f85a7084d22a1215a5a4b79920dc80 (diff)
downloadbcm5719-llvm-9c980cb50211431a1e8fc58639199389b0440f52.tar.gz
bcm5719-llvm-9c980cb50211431a1e8fc58639199389b0440f52.zip
[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. llvm-svn: 306137
-rw-r--r--clang/lib/AST/ExprConstant.cpp16
-rw-r--r--clang/test/CodeGenCXX/dllimport-memptr-global.cpp58
2 files changed, 74 insertions, 0 deletions
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 768947d00ac..60f8143c137 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/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<CXXMethodDecl>(Member);
+ if (!FD)
+ return true;
+ return FD->isVirtual() || !FD->hasAttr<DLLImportAttr>();
+}
+
/// 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/clang/test/CodeGenCXX/dllimport-memptr-global.cpp b/clang/test/CodeGenCXX/dllimport-memptr-global.cpp
new file mode 100644
index 00000000000..e64537b8b9f
--- /dev/null
+++ b/clang/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: }
OpenPOWER on IntegriCloud