Bug 89074 - valid pointer equality constexpr comparison rejected
Summary: valid pointer equality constexpr comparison rejected
Status: NEW
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 9.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords: rejects-valid
: 81781 (view as bug list)
Depends on:
Blocks: constexpr
  Show dependency treegraph
 
Reported: 2019-01-26 20:50 UTC by Tadeus Prastowo
Modified: 2021-11-18 16:14 UTC (History)
5 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail: 6.4.0, 7.3.0, 8.2.0, 9.0
Last reconfirmed: 2019-02-07 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Tadeus Prastowo 2019-01-26 20:50:01 UTC
struct A {
  static constexpr int v {1};
};
struct B {
  static constexpr int v {1};
};
static_assert(&A::v == &A::v, "1");
static_assert(&A::v != &B::v, "2");

According to http://eel.is/c++draft/expr.eq#3.3, the second static_assert should be successful.  But, while clang, icc, and msvc accept, gcc version 9.0.0 20190113 fails to even raise the assertion with the following message (https://www.godbolt.org/z/UtjS8v):

/tmp/x.cpp:10:21: error: non-constant condition for static assertion
   10 | static_assert(&A::v != &B::v, "2");
      |               ~~~~~~^~~~~~~~
/tmp/x.cpp:10:21: error: ‘((& A::v) != (& B::v))’ is not a constant expression
Comment 1 Martin Sebor 2019-02-07 21:23:51 UTC
Confirmed.  Not a regression.
Comment 2 Justin Bassett 2019-03-10 21:05:21 UTC
I also hit this bug: https://godbolt.org/z/EAinjd

template <typename T>
struct foo {
    static inline constexpr bool bar = {};
};

namespace {
    constexpr bool const* asdf1 = &foo<int>::bar;
    constexpr bool const* asdf2 = &foo<long int>::bar;
}

static_assert(asdf1 != asdf2);
Comment 3 Jakub Jelinek 2019-03-13 14:37:38 UTC
Another testcase:
template <int N>                                                                                                                                 
struct S {                                                                                                                                       
  static constexpr int a[2] = { 1, 2 };                                                                                                          
};                                                                                                                                               
static_assert (&S<0>::a[1] != nullptr);
Comment 4 Andrew Pinski 2021-07-27 09:30:53 UTC
*** Bug 81781 has been marked as a duplicate of this bug. ***
Comment 5 Jonathan Wakely 2021-11-18 14:18:05 UTC
I think this is another case of the same bug:

constexpr bool
test()
{
  int a[] = { 1, 2 };
  int b[] = { 3, 4 };

  if (a+0 == b+0)       // OK
    return false;

  if (a+1 == b+0)       // ERROR
    return false;

  return true;
}

static_assert( test() );


g++ -std=c++20 ce.C -c

ce.C:16:20: error: non-constant condition for static assertion
   16 | static_assert( test() );
      |                ~~~~^~
ce.C:16:20:   in 'constexpr' expansion of 'test()'
ce.C:10:11: error: '((((int*)(& a)) + 4) == ((int*)(& b)))' is not a constant expression
   10 |   if (a+1 == b+0)       // ERROR
      |       ~~~~^~~~~~
Comment 6 CVS Commits 2021-11-18 16:14:21 UTC
The master branch has been updated by Jonathan Wakely <redi@gcc.gnu.org>:

https://gcc.gnu.org/g:ca243ada71656651a8753e88164a1f0f019be1c3

commit r12-5376-gca243ada71656651a8753e88164a1f0f019be1c3
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Thu Nov 18 12:39:20 2021 +0000

    libstdc++: Fix std::char_traits<C>::move for constexpr
    
    The constexpr branch in __gnu_cxx::char_traits::move compares the string
    arguments to see if they overlap, but relational comparisons between
    unrelated pointers are not core constant expressions.
    
    I want to replace the comparisons with a loop using pointer equality to
    determine whether the end of the source string is in the destination
    string. However, that doesn't work with GCC, due to PR c++/89074 so
    allocate a temporary buffer instead and copy out into that first, so
    that overlapping source and destination don't matter. The allocation
    isn't supported by the current Intel icc so use the loop as a fallback.
    
    libstdc++-v3/ChangeLog:
    
            * include/bits/char_traits.h (__gnu_cxx::char_traits::move):
            Do not compare unrelated pointers during constant evaluation.
            * testsuite/21_strings/char_traits/requirements/constexpr_functions_c++20.cc:
            Improve tests for char_traits::move.