Bug 117700 - spurious error "non-constant condition" when inside a class member
Summary: spurious error "non-constant condition" when inside a class member
Status: RESOLVED DUPLICATE of bug 118249
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 14.2.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords: rejects-valid
Depends on:
Blocks: constexpr
  Show dependency treegraph
 
Reported: 2024-11-20 11:20 UTC by R. Diez
Modified: 2025-04-05 19:30 UTC (History)
3 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description R. Diez 2024-11-20 11:20:04 UTC
I am getting spurious errors "non-constant condition" and "use of 'this' in a constant expression" when retrieving the size of a fixed member array, but only from inside class members. The same expression works fine when outside the class member.

This is a demo:

#include <cstddef>

// This is like "sizeof(arr) / sizeof(arr[0])", but with fancy C++.
template <typename T, std::size_t N>
constexpr std::size_t ArrayElemCount ( T const (&)[N] ) noexcept
{
  return N;
}

class TestClass
{
public:
  int m_array[ 10 ];

  void test_method ( void ) const;
};

static TestClass test_instance;

// This works when checking from outside the class.
static_assert( ArrayElemCount( test_instance.m_array ) == 10 );

void TestClass::test_method ( void ) const
{
  // The traditional method still works from inside the class.
  static_assert( sizeof( m_array ) / sizeof( m_array[0]) == 10 );

  // But this fails when checking from inside the class.
  static_assert( ArrayElemCount( m_array ) == 10 );

  // The compilation errors with GCC 14.2 are:
  // error: non-constant condition for static assertion
  //        static_assert( ArrayElemCount( m_array ) == 10 );
  //                       ~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~
  // error: use of 'this' in a constant expression
}

You can play with it here:
https://godbolt.org/z/bYds71fWW
Comment 1 Drea Pinski 2024-11-20 22:49:16 UTC
Clang, edg and MSVC all reject it:
<source>:29:18: error: static assertion expression is not an integral constant expression
   29 |   static_assert( ArrayElemCount( m_array ) == 10 );
      |                  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<source>:29:34: note: implicit use of 'this' pointer is only allowed within the evaluation of a call to a 'constexpr' member function
   29 |   static_assert( ArrayElemCount( m_array ) == 10 );
      |                                  ^


GCC is correct here.
Comment 2 Drea Pinski 2024-11-20 22:51:02 UTC
This works though:

static_assert( std::size( decltype(m_array){} ) == 10 );
Comment 3 Drea Pinski 2024-11-20 23:03:57 UTC
even doing:
```
void f(const TestClass *a)
{

  // But this fails when checking from inside the class.
  static_assert( ArrayElemCount( a->m_array ) == 10 );

}
```

Will fail as `a->m_array ` is NOT a constexpr
BUT `test_instance.m_array` is one as the reference to test_instance is one too.
Comment 4 R. Diez 2024-11-21 09:49:42 UTC
I just found out some more information on this.

C++ is counterintuitive here, as template ArrayElemCount is only actually using type information.

This article considers it a language defect:
https://www.learncpp.com/cpp-tutorial/stdarray-length-and-indexing/

That article mentions that this C++ language issue has been addressed in C++23 by P2280:
https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2280r4.html

In the meantime, this C++11 implementation should do the trick. It uses a macro as an intermediate step, but I can live with it:
https://brnz.org/hbr/?p=1491
Comment 5 Drea Pinski 2024-11-30 04:58:23 UTC
So GCC tries to implement p2280r4 (see PR 106650) but maybe not fully after all.

Note p2280r4 is considered a fix for a defect too.
Comment 6 Marek Polacek 2025-02-12 22:10:32 UTC
clang++ implements p2280 and rejects the test the same.  I'm still not sure that there is a bug.
Comment 7 Patrick Palka 2025-04-05 19:26:39 UTC
(In reply to Andrew Pinski from comment #3)
> even doing:
> ```
> void f(const TestClass *a)
> {
> 
>   // But this fails when checking from inside the class.
>   static_assert( ArrayElemCount( a->m_array ) == 10 );
> 
> }
> ```
> 
> Will fail as `a->m_array ` is NOT a constexpr
> BUT `test_instance.m_array` is one as the reference to test_instance is one
> too.
IIUC the accepted revision of P2280 only allows unknown 'this', not pointers to unknown in general.
Comment 8 Patrick Palka 2025-04-05 19:28:55 UTC
The original testcase is basically a dup of PR118249, which has recently been fixed for GCC 15, so let's mark this one as a dup

*** This bug has been marked as a duplicate of bug 118429 ***
Comment 9 Drea Pinski 2025-04-05 19:30:41 UTC
swapped the 2 and 4 in the duplicated bug # :).

*** This bug has been marked as a duplicate of bug 118249 ***