summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang/lib/AST/ExprConstant.cpp35
-rw-r--r--clang/test/CodeGen/dllimport.c5
-rw-r--r--clang/test/Sema/dllimport.c8
-rw-r--r--clang/test/SemaCXX/PR19955.cpp8
4 files changed, 47 insertions, 9 deletions
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index c57a802512b..5897f2c4856 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -1269,11 +1269,36 @@ static bool CheckLValueConstantExpression(EvalInfo &Info, SourceLocation Loc,
LVal.getLValueCallIndex() == 0) &&
"have call index for global lvalue");
- // Check if this is a thread-local variable.
if (const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>()) {
if (const VarDecl *Var = dyn_cast<const VarDecl>(VD)) {
+ // Check if this is a thread-local variable.
if (Var->getTLSKind())
return false;
+
+ // Check if this is a dllimport variable. Fail evaluation if we care
+ // about side effects; a dllimport variable rarely acts like a constant
+ // except in places like template arguments. It never acts like a
+ // constant in C.
+ if ((!Info.getLangOpts().CPlusPlus ||
+ !Info.keepEvaluatingAfterSideEffect()) &&
+ Var->hasAttr<DLLImportAttr>())
+ return false;
+ }
+ if (const auto *FD = dyn_cast<const FunctionDecl>(VD)) {
+ // __declspec(dllimport) must be handled very carefully:
+ // We must never initialize an expression with the thunk in C++.
+ // Doing otherwise would allow the same id-expression to yield
+ // different addresses for the same function in different translation
+ // units. However, this means that we must dynamically initialize the
+ // expression with the contents of the import address table at runtime.
+ //
+ // The C language has no notion of ODR; furthermore, it has no notion of
+ // dynamic initialization. This means that we are permitted to
+ // perform initialization with the address of the thunk.
+ if (Info.getLangOpts().CPlusPlus &&
+ !Info.keepEvaluatingAfterSideEffect() &&
+ FD->hasAttr<DLLImportAttr>())
+ return false;
}
}
@@ -4373,11 +4398,8 @@ static bool EvaluateLValue(const Expr *E, LValue &Result, EvalInfo &Info) {
}
bool LValueExprEvaluator::VisitDeclRefExpr(const DeclRefExpr *E) {
- if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(E->getDecl())) {
- if (FD->hasAttr<DLLImportAttr>())
- return ZeroInitialization(E);
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(E->getDecl()))
return Success(FD);
- }
if (const VarDecl *VD = dyn_cast<VarDecl>(E->getDecl()))
return VisitVarDecl(E, VD);
return Error(E);
@@ -4393,9 +4415,6 @@ bool LValueExprEvaluator::VisitVarDecl(const Expr *E, const VarDecl *VD) {
Result.set(VD, Frame->Index);
return true;
}
- // The address of __declspec(dllimport) variables aren't constant.
- if (VD->hasAttr<DLLImportAttr>())
- return ZeroInitialization(E);
return Success(VD);
}
diff --git a/clang/test/CodeGen/dllimport.c b/clang/test/CodeGen/dllimport.c
index 485f6e21b2a..32ee81f8592 100644
--- a/clang/test/CodeGen/dllimport.c
+++ b/clang/test/CodeGen/dllimport.c
@@ -53,7 +53,10 @@ USEVAR(GlobalRedecl3)
// Import function declaration.
// CHECK-DAG: declare dllimport void @decl()
__declspec(dllimport) void decl(void);
-USE(decl)
+
+// Initialize use_decl with the address of the thunk.
+// CHECK-DAG: @use_decl = global void ()* @decl
+void (*use_decl)(void) = &decl;
// Import inline function.
// CHECK-DAG: declare dllimport void @inlineFunc()
diff --git a/clang/test/Sema/dllimport.c b/clang/test/Sema/dllimport.c
index f4d26fb8c87..2702453b61c 100644
--- a/clang/test/Sema/dllimport.c
+++ b/clang/test/Sema/dllimport.c
@@ -25,6 +25,9 @@ __declspec(dllimport) int GlobalDecl;
int **__attribute__((dllimport))* GlobalDeclChunkAttr;
int GlobalDeclAttr __attribute__((dllimport));
+// Address of variables can't be used for initialization in C language modes.
+int *VarForInit = &GlobalDecl; // expected-error{{initializer element is not a compile-time constant}}
+
// Not allowed on definitions.
__declspec(dllimport) extern int ExternGlobalInit = 1; // expected-error{{definition of dllimport data}}
__declspec(dllimport) int GlobalInit1 = 1; // expected-error{{definition of dllimport data}}
@@ -96,6 +99,11 @@ __declspec(dllimport) void decl1B();
void __attribute__((dllimport)) decl2A();
void __declspec(dllimport) decl2B();
+// Address of functions can be used for initialization in C language modes.
+// However, the address of the thunk wrapping the function is used instead of
+// the address in the import address table.
+void (*FunForInit)() = &decl2A;
+
// Not allowed on function definitions.
__declspec(dllimport) void def() {} // expected-error{{dllimport cannot be applied to non-inline function definition}}
diff --git a/clang/test/SemaCXX/PR19955.cpp b/clang/test/SemaCXX/PR19955.cpp
index e0d4618f2c4..4596e5a459e 100644
--- a/clang/test/SemaCXX/PR19955.cpp
+++ b/clang/test/SemaCXX/PR19955.cpp
@@ -5,3 +5,11 @@ constexpr int *varp = &var; // expected-error {{must be initialized by a constan
extern __attribute__((dllimport)) void fun();
constexpr void (*funp)(void) = &fun; // expected-error {{must be initialized by a constant expression}}
+
+template <void (*)()>
+struct S {};
+S<&fun> x;
+
+template <int *>
+struct U {};
+U<&var> y;
OpenPOWER on IntegriCloud