Skip to content

Clang and GCC differ in instantiation strategy of constexpr and incomplete types #59966

@ilya-biryukov

Description

@ilya-biryukov

Consider this code compiled in C++20 mode:

#include <vector>

struct X{
    struct Inner;
    unsigned size() { return children.size(); }
    std::vector<Inner> children;
};

struct X::Inner {
    int a;
};

MSVC and GCC will succeed, but Clang (trunk, WIP version 16 at the time of writing) produces an error:

/lib/gcc/x86_64-linux-gnu/13.0.0/../../../../include/c++/13.0.0/bits/stl_vector.h:988:50: error: arithmetic on a pointer to an incomplete type 'X::Inner'
      { return size_type(this->_M_impl._M_finish - this->_M_impl._M_start); }

This boils down to different approaches when instantiating constexpr functions:

template <class T>
struct vector {
    T* ptr;
    constexpr unsigned size() { return ptr - ptr; }
};

struct X{
    struct Inner;
    unsigned size() { return children.size(); }
    vector<Inner> children;
};

struct X::Inner {
    int a;
};

Clang instantiates the bodies of constexpr functions eagerly, other compilers seem to delay the instantiation until the end of the TU, e.g. this code fails in all compilers:

template <class T>
struct vector {
    T* ptr;
    constexpr unsigned size() { return ptr - ptr; }
};

struct X{
    struct Inner;
    static constexpr int a = vector<Inner>().size();
    vector<Inner> children;
};

struct X::Inner {
    int a;
};

We have observed that this pattern is used in much of the existing code and I believe Clang should follow the GCC's and MSVC's approach here, even though it is not mandated by the standard:

  • it avoids breaking code that worked in C++17 when migrating to C++20.
  • it allows to compile future C++20 code written for GCC and MSVC with Clang with no changes.

Metadata

Metadata

Assignees

No one assigned

    Labels

    c++20clang:frontendLanguage frontend issues, e.g. anything involving "Sema"

    Type

    No type

    Projects

    Status

    No status

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions