LLVM Bugzilla is read-only and represents the historical archive of all LLVM issues filled before November 26, 2021. Use github to submit LLVM bugs

Bug 33796 - availability attributes override visibility
Summary: availability attributes override visibility
Status: RESOLVED FIXED
Alias: None
Product: clang
Classification: Unclassified
Component: C++ (show other bugs)
Version: unspecified
Hardware: PC All
: P enhancement
Assignee: Unassigned Clang Bugs
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2017-07-14 17:39 PDT by Nico Weber
Modified: 2017-08-08 10:22 PDT (History)
6 users (show)

See Also:
Fixed By Commit(s):


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Nico Weber 2017-07-14 17:39:52 PDT
We're moving Chrome to @available, which requires tagging some of our code with API_AVAILABLE(10.10). However, that seems to also make classes visible, which we don't want:

$ cat test.cc
#define F
class F Foo {
  void f();
};

void Foo::f() {}
$ bin/clang -c test.cc -mmacosx-version-min=10.10 -fvisibility=hidden -fvisibility-inlines-hidden && ld -dylib -o libtest.dylib test.o && nm libtest.dylib 
ld: warning: -macosx_version_min not specified, assuming 10.10
0000000000000fb0 t __ZN3Foo1fEv

$ cat test.cc
#define F __attribute__((availability(macos, introduced=10.11))) 
class F Foo {
  void f();
};

void Foo::f() {}
$ bin/clang -c test.cc -mmacosx-version-min=10.10 -fvisibility=hidden -fvisibility-inlines-hidden && ld -dylib -o libtest.dylib test.o && nm libtest.dylib 
ld: warning: -macosx_version_min not specified, assuming 10.10
0000000000000fb0 T __ZN3Foo1fEv



That's hopefully just a bug, and not by design?
Comment 1 Erik Pilkington 2017-07-14 17:44:22 PDT
This is probably because of Decl::isWeakImported(), which returns true if the decl is AR_NotYetIntroduced. I'm taking a look.
Comment 2 Erik Pilkington 2017-07-14 18:25:09 PDT
Scratch that, looks like the problem is r128336, which makes an availability attribute imply default vis just on macOS. I have no idea why we're doing that, I'll ask around on Monday. 

If your looking for a temporary workaround, explicitly annotating the decl with hidden visibility seems to get your message across to clang code gen.
Comment 3 Alex Lorenz 2017-07-16 06:37:58 PDT
I didn't see a radar number in that commit anywhere, hopefully Doug will remember what this change was about.
Comment 4 Duncan 2017-07-16 06:52:32 PDT
As a workaround, does adding __visibility__("hidden") on these work?
Comment 5 Nico Weber 2017-07-16 17:08:58 PDT
 __visibility__("hidden") works as a workaround.

It's a bit clunky though: We have a (fairly standard, I believe) build setup where in production builds we build a single staticly-linked binary with -fvisibility=hidden that doesn't export most things, and then in developer builds we have many small .dylibs that each export a bunch of functions. To this end, we have COMPONENT_EXPORT macros for each component that expand to nothing in production builds but to __attribute__((visibility("default"))) in the dylib builds. If API_AVAIL implies default visibility, and it needs to be specified on a class that's exported in dylib builds, we now need to say

class API_AVAIL attribute((visibility("hidden"))) FOO_EXPORT MyClass { ... };

in that exact order. We could use our own CR_API_AVAIL macro that's defined to "API_AVAIL API_AVAIL attribute((visibility("hidden")))" and then use that everywhere, but then people still need to remember to put _EXPORT after that, and it means we need a wrapper macro for API_AVAIL.

So it's an ok short-term workaround, but it'd be nice to have some way to use API_AVAILABILITY and have it not imply default visibility. If changing the semantics of __attribute__((availability(macos, introduced=10.11))) turns out to be infeasible, maybe there could be a __attribute__((availability(macos, just_introduced=10.11))) thing (name tbd) that doesn't imply visibility, only introduced-ness. Then API_AVAILABILITY could maybe use that, or we could have our own macro using that thing, and then people at least don't have to remember the order of CR_API_AVAIL and _EXPORT.
Comment 6 Duncan 2017-07-16 17:28:25 PDT
Glad it works.  Agreed it’s clunky.

The current behaviour doesn’t make much sense to me; likely some sort of historical hack.  I hope we can undo it.
Comment 7 Juergen Ributzka 2017-07-17 11:21:37 PDT
It kinda makes sense, because we usually use the availability attribute for annotating public API in the SDK. Any public API that is available also needs to be exported/visible, otherwise the API would be quite useless.

I am just guessing here and defer to Doug for the history on this, but I am fairly certain quite some code still depends on this historical behavior and might break if we change it.
Comment 8 Erik Pilkington 2017-07-17 11:29:12 PDT
(In reply to Juergen Ributzka from comment #7)
> It kinda makes sense, because we usually use the availability attribute for
> annotating public API in the SDK. Any public API that is available also
> needs to be exported/visible, otherwise the API would be quite useless.

But why just on macOS? Doesn't that argument hold for the other platforms? 

Turns out Doug is out of town until next week. I'll CC him to this, but I guess this will probably have to wait until he comes back...
Comment 9 Juergen Ributzka 2017-07-17 11:36:29 PDT
Like with most historical workarounds we sometimes manage to clean them up with new platforms.
Comment 10 Nico Weber 2017-07-17 13:49:00 PDT
(In reply to Juergen Ributzka from comment #7)
> It kinda makes sense, because we usually use the availability attribute for
> annotating public API in the SDK. Any public API that is available also
> needs to be exported/visible, otherwise the API would be quite useless.

I can see how this makes sense for SDK headers. But with @available, user code is now using API_AVAILABLE too, and there having some way to annotation just availability without impacting visibility is needed.
Comment 11 Nico Weber 2017-07-28 09:24:50 PDT
Any news here?

Since clang warns on duplicate attrib(visibility), this currently requires this for the setup described in comment 5:

#if defined(UI_BASE_IMPLEMENTATION) && defined(COMPONENT_BUILD)
// UI_BASE_EXPORT specifies "default" visibility.
API_AVAILABLE(macosx(10.12.2))
#else
API_AVAILABLE(macosx(10.12.2))
__attribute__((visibility("hidden")))
#endif
UI_BASE_EXPORT NSButton* GetBlueTouchBarButton(NSString* title,
                                               id target,
                                               SEL action);

(from https://cs.chromium.org/chromium/src/ui/base/cocoa/touch_bar_util.h?type=cs&q=API_AVAILABLE&sq=package:chromium&l=46)
Comment 12 Erik Pilkington 2017-07-28 09:27:32 PDT
(In reply to Nico Weber from comment #11)
> Any news here?

Yep, I talked with Doug Gregor and he had the idea of only having this behavior in system headers. I have a patch for this, but I have to test it out with some stuff to make sure nothing breaks. Hopefully I'll have a patch up later today.

> 
> Since clang warns on duplicate attrib(visibility), this currently requires
> this for the setup described in comment 5:
> 
> #if defined(UI_BASE_IMPLEMENTATION) && defined(COMPONENT_BUILD)
> // UI_BASE_EXPORT specifies "default" visibility.
> API_AVAILABLE(macosx(10.12.2))
> #else
> API_AVAILABLE(macosx(10.12.2))
> __attribute__((visibility("hidden")))
> #endif
> UI_BASE_EXPORT NSButton* GetBlueTouchBarButton(NSString* title,
>                                                id target,
>                                                SEL action);
> 
> (from
> https://cs.chromium.org/chromium/src/ui/base/cocoa/touch_bar_util.
> h?type=cs&q=API_AVAILABLE&sq=package:chromium&l=46)

Yikes! Thats pretty ugly.
Comment 13 Alex Lorenz 2017-08-01 09:00:54 PDT
We will probably have to change this behaviour so that the symbol's visibility is not affected.