Re: cfe-dev Digest, Vol 156, Issue 156

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view

Re: cfe-dev Digest, Vol 156, Issue 156

Vassil Vassilev via cfe-dev

In any case, I concur with Louis that this seems like it'd have to be done at the C++ level, not the preprocessor level.

The semantics of my hypothetical "__using_if_exists QUALNAME;" declaration are that it does a name lookup on QUALNAME, and then if the lookup fails it does nothing, and if the lookup succeeds it acts like a regular `using` declaration. This feels like it should be super easy to implement as a compiler extension, right?

Yes, that's exactly what I was asking. I wondered whether folks could spot a fundamental issue with doing this, but it looks like perhaps there is none.

Bikeshed: __using_if_exists, __using_or_ignoring, __using_if_present, __using_unless_absent, __using_maybe_absent.

But, doesn't libc++ also need to work with GCC and maybe other compilers too? So won't you need to convince those compilers to implement whatever you pick here, or else keep the existing preprocessor hacks around forever anyway?

AFAICT, libc++ works with recent-ish GCCs and Clang, that's it. There's been some work for it to work on other compilers, but none of it is maintained, and all of it is probably broken -- as far as I'm aware.

If we went down that route, I'd kindly ask GCC to implement the same builtin, and if they say no, I could always resort to:

#if defined(__GNUC__)
#  define _LIBCPP_USING_IF_EXISTS(...) using __VA_ARGS__
#  define _LIBCPP_USING_IF_EXISTS(...) __using_if_exists __VA_ARGS__

Or whatever form that ends up taking. I might have to keep existing workarounds for a little bit, but it would be reasonable to require that this extension be supported in order to add support for a new platform. Otherwise the headers just become a huge spaghetti.


It’s always best, when encountering issues like this, to solve them in the most generic way possible so that laypeople could benefit from our efforts as well.  That’s why I would favor solving this using reflection/reification techniques that we will want users to eventually be using anyway.  My original detailed reply from early this morning seems not to have gone through, looking at the thread online, so I’ll reproduce it here just to be sure it’s considered, since this is a perfect motivating case for these more general techniques.  Thanks and good luck,


My original reply:


I’ll take a shot.  About a year ago I developed what I call a "metaparse" statement node for clang, intended to work with a reflection implementation I developed alongside it, which in a sense brings preprocessor expansion ability into constexpr evaluation.

Assume for now __has_declaration is already defined:

consteval { //a "metaprogram"

if (__has_declaration(::FILE))
__queue_metaparse("using ::FILE;");
if (__has_declaration(::fpos_t))
__queue_metaparse("using ::fpos_t;");
if (__has_declaration(::size_t))
__queue_metaparse("using ::size_t;");
__queue_metaparse("static const int TestVar = 3;");

} //...queued metaparses performed here, placing parsed decls into outer scope...


If you wanted to define __has_declaration via what I call my "mirror-image reflection" implem, rather than via a new built-in: you would first probably want to define a public clang::DeclContext method "bool hasDeclNamed(StringRef name)" to handle the lookup, then after building clang-wreflection that method would be available in all reflected DeclContexts.  Then:

#define __has_declaration(NAME) __clangreflexpr(::/*reflects the translation unit*/)->hasDeclNamed(#NAME)

The following is old code I have not updated in awhile, and the readme/documentation is a mess, but you'll get the gist.

The reflection stuff did not catch on here because the clang folks did not want the clang AST interface to be exposed via reflection, as it is not stable.  But I was very surprised at least the metaparsing portion did not catch on — it’s a great general purpose tool that would work with any reflection implementation, or in other metaprogramming situations such as yours, and is dirt-simple to understand and use.  

FWIW Microsoft seemed to get the idea, and several months after my release added what they call "source generators" to C# which seems to work in this way.  (See their sourceBuilder.append(…) stuff.  No attribution though :/).

Bottom line, to do these sorts of things in general we need reflection + its inverse ("reification" as some call it), and metaparsing or source generation or whatever you want to call seems to be the most straightforward and general solution for that latter task.

Hope that helps the brainstorming, good luck,


cfe-dev mailing list
[hidden email]