diff options
| author | David Majnemer <david.majnemer@gmail.com> | 2014-06-25 08:15:07 +0000 |
|---|---|---|
| committer | David Majnemer <david.majnemer@gmail.com> | 2014-06-25 08:15:07 +0000 |
| commit | 0c43d8077e605ab78d85180f0dcaa4df1ae37607 (patch) | |
| tree | 5eaaea1e9c5d0a51430e084622303fb3af963572 /clang/test/Sema/dllimport.c | |
| parent | 01ecd3107e6475722249deee010755690f0a91be (diff) | |
| download | bcm5719-llvm-0c43d8077e605ab78d85180f0dcaa4df1ae37607.tar.gz bcm5719-llvm-0c43d8077e605ab78d85180f0dcaa4df1ae37607.zip | |
AST: Initialization with dllimport functions in C
The C++ language requires that the address of a function be the same
across all translation units. To make __declspec(dllimport) useful,
this means that a dllimported function must also obey this rule. MSVC
implements this by dynamically querying the import address table located
in the linked executable. This means that the address of such a
function in C++ is not constant (which violates other rules).
However, the C language has no notion of ODR nor does it permit dynamic
initialization whatsoever. This requires implementations to _not_
dynamically query the import address table and instead utilize a wrapper
function that will be synthesized by the linker which will eventually
query the import address table. The effect this has is, to say the
least, perplexing.
Consider the following C program:
__declspec(dllimport) void f(void);
typedef void (*fp)(void);
static const fp var = &f;
const fp fun() { return &f; }
int main() { return fun() == var; }
MSVC will statically initialize "var" with the address of the wrapper
function and "fun" returns the address of the actual imported function.
This means that "main" will return false!
Note that LLVM's optimizers are strong enough to figure out that "main"
should return true. However, this result is dependent on having
optimizations enabled!
N.B. This change also permits the usage of dllimport declarators inside
of template arguments; they are sufficiently constant for such a
purpose. Add tests to make sure we don't regress here.
llvm-svn: 211677
Diffstat (limited to 'clang/test/Sema/dllimport.c')
| -rw-r--r-- | clang/test/Sema/dllimport.c | 8 |
1 files changed, 8 insertions, 0 deletions
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}} |

