clang, static/inline, and windows.h

List,

I am working on having clang parse a recent windows.h header. I am
encountering great success, however I have one problem with inlined
functions. In winnt.h, there are a series of definitions for
Int64ShllMod32 and related functions, these functions are defined as
__inline. Compiling a multi file project with clang produces errors
because these functions appear more than once and at link time
collisions occur.

The problem seems to stem from the functions not being defined as
'static'. If the functions are defined as static, they are inlined and
removed during compilation. Without the static definition, the
optimizer doesn't know it is safe to remove the functions after they
have been inlined.

It seems that MSVC silently promotes any function declared __inline or
__forceinline to static (or something equivalent/similar). My thinking
is adding in a "compatibility" layer to clang so that when dealing
with windows header files clang also promotes any function defined as
inline to static storage. What does the list think? Is this a good
idea? If it is, where would a good place to start in clang be to
implement it? If it isn't a good idea, what would be?

Thank you,

Andrew

It sounds like __inline is equivalent to static inline and __forceinline to __attribute__((always_inline)) in this case. Perhaps the solution is to do do the same thing that we do for __block, and just define __inline and __forceinline as predefined macros when in MS mode?

David

-- Sent from my Apple II

There is one wrinkle I forgot to add, and I'm not sure how much it
changes. Consider the following declarations:

int a1(int k);

__inline int a1(int k) { return k; }

this happens with Int64ShllMod32 in winnt.h. I hacked clang so that it
would interpret __inline and __forceinline as static and set the
function storage class appropriately, but the previous definitions
cause clang to error since then it would see it as:

int a1(int k);

static inline int a1(int k){ ... }

which is bad.

__inline is a keyword for GCC already, isn't it? it seems to be
aliased to "inline" in the td file.

What do you mean by MS mode? Where is that controlled?

Thank you,

Andrew

This is most likely due to Clang defaulting to C99 and its inline semantics, rather than the inline semantics used (e.g.) by GNU C or C++. As a simple experiment, try adding

  -std=gnu89

to your command line.

See

  http://clang.llvm.org/compatibility.html#inline

for more information.

  - Doug

Doug,

Thanks for that link!

I tried compiling with -std=gnu89, it definitely changed the behavior.
Passing that seemed to undo a previous change I had made, I replaced
the //FIXME on line 1208 in lib/Parse/ParseDecl.cpp (from 2.9 tag)
with

isInvalid = DS.SetFunctionSpecInline(Loc, PrevSpec, DiagID);

which seemed to be the right thing to do and when compiling in C99,
inlined functions that weren't referenced weren't present in resulting
bc files. UNLESS, my uneducated and slapdash hackery caused some
massively deleterious change that only APPEARED to do what I want
(which is very possible).

As an experiment, I compiled with -std=gnu89 and didn't notice a
change. This definition was in a header:

inline int a1(int k) {
        return k >> 5;
}

compiled with the following switches:

clang -c -emit-llvm -x c -std=gnu89 -o t1.bc t1.c

and this definition was in the resulting bitcode file:

define i32 @a1(i32 %k) nounwind inlinehint {
entry:
  %k.addr = alloca i32, align 4
  store i32 %k, i32* %k.addr, align 4
  %tmp = load i32* %k.addr, align 4
  %shr = ashr i32 %tmp, 5
  ret i32 %shr
}

Without "internal" specification, that would cause a problem with
anything that included the header that defined a1, wouldn't it? Or am
I missing something?

Thank you very much for your response,

Andrew

To clarify, MSVC in C mode actually uses C++-style semantics for
__inline, not the gnu89 or C99 semantics; see
http://llvm.org/bugs/show_bug.cgi?id=9392 .

-Eli