Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

clang seems to be overzealous with lifetime errors in constexpr #53494

Open
TobiSchluter opened this issue Jan 31, 2022 · 3 comments
Open

clang seems to be overzealous with lifetime errors in constexpr #53494

TobiSchluter opened this issue Jan 31, 2022 · 3 comments
Labels
clang:frontend Language frontend issues, e.g. anything involving "Sema"

Comments

@TobiSchluter
Copy link

TobiSchluter commented Jan 31, 2022

Consider this (derived from the Eigen library, tested with clang 13.0.0 and clang 12)

struct B;

#define CONSTEXPR constexpr
#define CONSTEVAL consteval

struct A {
public:
    CONSTEXPR A() { m_val = 1; }
    CONSTEXPR A(const A& other) { m_val = other.m_val;}
    CONSTEXPR ~A() {};

    CONSTEXPR int val() { return m_val; }

    int m_val;

    CONSTEXPR B operator<<(int);
};

struct B {
    A& m_a;
    CONSTEXPR B(A& ref) : m_a(ref) {}
    CONSTEXPR B& operator,(int i) { m_a.m_val = i; return *this; }
    CONSTEXPR ~B() { finished(); }
    CONSTEXPR A finished() { return m_a; }
};

CONSTEXPR B A::operator<<(int i) {
    m_val = i;
    return B(*this);
}

CONSTEVAL int f()
{
    A a{(A() << 1, 2, 3, 4).finished()};
    return a.val();
}

int g()
{
    return f();
}

Godbolt link here: https://godbolt.org/z/njfxf9jP5

As you can see in GCC's intermediate output (obtained by disabling constexpr via macros), ~B is always called before ~A. Nevertheless, clang prints

source>:44:12: error: call to consteval function 'f' is not a constant expression
    return f();
           ^
<source>:13:43: note: read of object outside its lifetime is not allowed in a constant expression
    CONSTEXPR A(const A& other) { m_val = other.m_val;}
                                          ^
<source>:28:37: note: in call to 'A(A())'
    CONSTEXPR A finished() { return m_a; }
                                    ^
<source>:27:22: note: in call to '&A() << 1->finished()'
    CONSTEXPR ~B() { finished(); }
                     ^
<source>:38:10: note: in call to '&A() << 1->~B()'
    A a{(A() << 1, 2, 3, 4).finished()};
         ^
<source>:44:12: note: in call to 'f()'
    return f();
           ^

(I think clang is wrong here, but of course gcc may be getting the destruction order wrong.)

@EugeneZelenko EugeneZelenko added clang:frontend Language frontend issues, e.g. anything involving "Sema" and removed new issue labels Jan 31, 2022
@llvmbot
Copy link
Collaborator

llvmbot commented Jan 31, 2022

@llvm/issue-subscribers-clang-frontend

@Phytolizer
Copy link

I've got a more minimal example that seems to be related.

#include <iostream>
#include <memory>

consteval int something() {
  int *p = std::allocator<int>().allocate(1);
  *p = 5;
  int x = *p;
  std::allocator<int>().deallocate(p, 1);
  return x;
}

int main() { std::cout << something() << '\n'; }

Godbolt link: https://godbolt.org/z/6GKnnq4c6

@shafik
Copy link
Collaborator

shafik commented May 16, 2022

@Phytolizer Your example may not be equivalent, allocate() does not start of the element see [allocator.members]p5.

If you add std::construct_at<int>(p); it now is well-formed: https://godbolt.org/z/TTeYq6KxP

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:frontend Language frontend issues, e.g. anything involving "Sema"
Projects
None yet
Development

No branches or pull requests

5 participants