Skip to content

Generated C drops vector_size from a std::remove_cv<V>::type typedef when V is a vector type deduced by a conversion function #441

Open

Description

@mborland

Issue Summary

When std::remove_cv<V>::type is used inside a conversion function template
and V is a GNU vector type deduced from the conversion's target type, the
resulting typedef is emitted in the generated C as the element type
(long long) without __attribute__((vector_size(16))). gcc then rejects the
generated C with "incompatible types". g++ accepts the source.

Boost.UUID's simd_vector is this pattern, so every translation unit that
formats UUIDs with SSE2 (<boost/uuid/uuid_io.hpp>) fails to compile. In the
Boost test suite this fails 13 Boost.Unordered tests (the mmap,
interprocess-concurrency and visualization tests).

Reproducing Source Code

namespace std {
template <class T> struct remove_cv { using type = __remove_cv(T); };
}

typedef long long m128 __attribute__((__vector_size__(16)));

struct S {
  alignas(16) unsigned char bytes[16];
  template <typename V> operator V() const {
    using vector_type = typename std::remove_cv<V>::type;
    return *reinterpret_cast<const vector_type *>(bytes);
  }
};

m128 f(const S &s) { return s; }

Command-line Options

EDG_USE_SYSTEM_HEADERS=1 eccp --c++17 -c remove_cv_vector.cpp -o remove_cv_vector

Type of Issue

[Back End] There is a problem with the generated C code.

Additional Details

Expected: compiles (g++ 15.3.1 compiles it).
Actual (linux-gcc-release and linux-gcc-debug):

eccp: diagnostics generated from compilation of remove_cv_vector.int.c:
remove_cv_vector.cpp: In function '_ZNK1ScvT_IDv2_xEEv':
remove_cv_vector.cpp:11:8: error: incompatible types when returning type '_ZZNK1ScvT_IDv2_xEEvE11vector_type' {aka 'long long int'} but '__vector(2) long long int' was expected
eccp: end of diagnostics from compilation of remove_cv_vector.int.c
eccp: gcc compilation of remove_cv_vector.int.c returned an exit status of 1

Generated C:

typedef long long _ZZNK1ScvT_IDv2_xEEvE11vector_type;

What it depends on (each variant checked separately):

  • The template has to be std::remove_cv itself. Renaming it (std::rc) or
    moving it out of std (foo::remove_cv) gives a correct typedef of the
    member typedef, which is emitted with __attribute((vector_size(16))).
  • V has to be deduced through the conversion function, which gives an
    unnamed vector type (mangled Dv2_x). std::remove_cv<m128>::type with the
    named typedef works, and so does using vector_type = V;.
  • libstdc++'s own <type_traits> reproduces it too:
    typename std::remove_cv<typename std::remove_reference<V>::type>::type
    (libstdc++ 15 defines both with __remove_cv/__remove_reference).

std::remove_cv<T>::type is one of the front end's type-member intrinsics
(NS_templ_type_member_intrinsics, src/sys_predef.h:135; resolved by
subst_std_remove_cv, src/sys_predef.c:153, added in 296c4f4). It
returns the template argument type directly, without instantiating the class.
For a deduced vector type the typedef produced this way loses its vector
attribute somewhere before the C back end emits it. I didn't track down
exactly where. std::remove_reference, std::remove_const,
std::remove_volatile and std::remove_cvref use the same mechanism, so they
are probably affected too.

Boost: boost/uuid/detail/simd_vector.hpp. operator Vector() (line 28)
calls get<Vector>() (lines 36-41), which does
using vector_type = typename std::remove_cv<typename std::remove_reference<Vector>::type>::type;
and boost/uuid/detail/to_chars_x86.hpp:333 converts simd_vector constants
to __m128i. A 4-line TU that includes <boost/uuid/uuid_io.hpp> and calls
to_string(uuid) fails the same way, with or without --no_inlining.

Environment: edgcpp/dev-env Docker image (Fedora 43, GCC 15.3.1) on
x86-64, boost branch at c36e03a67c. EDG_USE_SYSTEM_HEADERS=1 makes eccp
use GCC 15's headers and pass --gnu_version=150301
(bases/docker/dev-env/gcc/edg_eccp_config).

Reproducing (Standard) Configuration(s)

linux-gcc-debug

Reproducing (Non-standard) Configuration

No response

I acknowledge that:

  • I have checked open issues and existing discussions before filing this report.
  • The reproducing source code that I have provided does not depend on headers that I have not included with my submission.
  • I have reduced the reproducing source code to the best of my ability.
  • I have selected at least one standard configuration or uploaded a non-standard configuration dump.
  • I understand code shared via this form is NOT confidential.
  • I have permission to share the reproducing source code and grant permission for the project to use the source code (or derivatives of the source code) to create tests.
  • I agree that any tests created using the reproducing source code (or deriatives of it) will be licensed under project license unless I included a LICENSE.txt file in my .zip or .tar.gz upload. If I included a LICENSE.txt file, any tests created using the reproducing source code will be governed by the terms of the license I provided instead.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions