[Bug 205453] 11.0-CURRENT libcxxrt/guard.cc uses C11's _Static_assert in conditionally-compiled C++ code and when it is used buildworld fails for syntax errors in g++ compilers

bugzilla-noreply at freebsd.org bugzilla-noreply at freebsd.org
Sun Dec 20 07:37:13 UTC 2015


https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=205453

            Bug ID: 205453
           Summary: 11.0-CURRENT libcxxrt/guard.cc uses C11's
                    _Static_assert in conditionally-compiled C++ code and
                    when it is used buildworld fails for syntax errors in
                    g++ compilers
           Product: Base System
           Version: 11.0-CURRENT
          Hardware: ppc
                OS: Any
            Status: New
          Severity: Affects Only Me
          Priority: ---
         Component: bin
          Assignee: freebsd-bugs at FreeBSD.org
          Reporter: markmi at dsl-only.net

[There might be some debate if g++ compilers should directly support C11's
_Static_assert. I've pick the component to submit under under the answer "no".]

A 6 line program can show the behavior of FreeBSD's sys/cdefs.h's
_Static_assert handling vs. g++ compilers for C++ code that ties to use
_Static_assert, even in contexts where libcxxrt/gaurd.cc is not involved:

# more main.cc
#include "/usr/include/sys/cdefs.h"
_Static_assert(1,"Test");
int main(void)
{
    return 0;
}

For example:

# g++49 main.cc
main.cc:2:15: error: expected constructor, destructor, or type conversion
before '(' token
 _Static_assert(1,"Test");
               ^
This is also true with the include commented out as well.

g++49, g++5, and powerpc64-portbld-freebsd11.0-g++ all reject the above source
the same way that libcxxrt/guard.cc compiles are rejected during
powerpc64-portbld-freebsd11.0-g++ based buildworld lib32 -m32 compiles. 

gcc49, gcc5, and powerpc64-portbld-freebsd11.0-gcc all accept the above instead
(when in main.c instead of main.cc so it is handle as C code), with or without
the include. _Static_assert is specific to C11 and is not part of C++. It takes
explicit definitions to make the syntax acceptable as C++.

Note: clang++ (3.7) accepts the use of the C11 _Static_assert, with or without
the include, going well outside the C++ language definition.

With that as the simplified-context the FreeBSD details involved in the
buildworld failures are:

The sys/cdefs.h include is not (re-)defining the _Static_assert notation for
C++ compiles by g++ compilers to translate to C++ notation or to any syntax
acceptable to the g++ compilers. The following sys/cdefs.h code seems to assume
that if _Static_assert is supported for gcc it is also supported for g++, which
is not currently the case because of the distinct languages involved.

#if !__has_extension(c_static_assert)
#if (defined(__cplusplus) && __cplusplus >= 201103L) || \
    __has_extension(cxx_static_assert)
#define _Static_assert(x, y)    static_assert(x, y)
#elif __GNUC_PREREQ__(4,6)
/* Nothing, gcc 4.6 and higher has _Static_assert built-in */
#elif defined(__COUNTER__)
#define _Static_assert(x, y)    __Static_assert(x, __COUNTER__)
#define __Static_assert(x, y)   ___Static_assert(x, y)
#define ___Static_assert(x, y)  typedef char __assert_ ## y[(x) ? 1 : -1] \
                                __unused
#else
#define _Static_assert(x, y)    struct __hack
#endif

Why a C++ source is using a C11-only declaration syntax instead of a C++ syntax
I do not know. But as long as FreeBSD does such it would appear that the above
code was supposed to provide a translation to C++ syntax --or for g++ to a g++
compatible syntax. Otherwise libcxxrt/guard.cc just needs to be fixed to be C++
compliant (spanning fairly modern clang++ and g++).

The libcxxrt/guard.cc non-arm/non-LP64/non-little-endian context comes from the
#if/#elif/. . . structure:

#ifdef __arm__
. . .
#elif defined(_LP64)
. . .
#else
typedef uint32_t guard_lock_t;
#       if defined(__LITTLE_ENDIAN__)
. . .
#       else
typedef struct {
        uint32_t init_half;
        uint32_t lock_half;
} guard_t;
_Static_assert(sizeof(guard_t) == sizeof(uint64_t), "");
static const uint32_t LOCKED = 1;
static const uint32_t INITIALISED = static_cast<guard_lock_t>(1) << 24;
#       endif
#define LOCK_PART(guard) (&(guard)->lock_half)
#define INIT_PART(guard) (&(guard)->init_half)
#endif

An example of the buildworld failure that reached the _Static_assert is:

--- guard.po ---
/usr/local/bin/powerpc64-portbld-freebsd11.0-g++ -m32 -mcpu=powerpc . . .   -c
/usr/src/lib/libcxxrt/../../contrib/libcxxrt/guard.cc -o guard.po
. . .
--- guard.po ---
/usr/src/lib/libcxxrt/../../contrib/libcxxrt/guard.cc:104:15: error: expected
constructor, destructor, or type conversion before '(' token
 _Static_assert(sizeof(guard_t) == sizeof(uint64_t), "");

-- 
You are receiving this mail because:
You are the assignee for the bug.


More information about the freebsd-bugs mailing list