Commit 131b4620 authored by Corentin Jabot's avatar Corentin Jabot Committed by Aaron Ballman
Browse files

Implement P1937 consteval in unevaluated contexts

In an unevaluated contexts, consteval functions should not be
immediately evaluated.
parent 3c8e94bc
Loading
Loading
Loading
Loading
+4 −3
Original line number Diff line number Diff line
@@ -16641,7 +16641,8 @@ void Sema::CheckUnusedVolatileAssignment(Expr *E) {
}
ExprResult Sema::CheckForImmediateInvocation(ExprResult E, FunctionDecl *Decl) {
  if (!E.isUsable() || !Decl || !Decl->isConsteval() || isConstantEvaluated() ||
  if (isUnevaluatedContext() || !E.isUsable() || !Decl ||
      !Decl->isConsteval() || isConstantEvaluated() ||
      RebuildingImmediateInvocation)
    return E;
@@ -18758,8 +18759,8 @@ void Sema::MarkDeclRefReferenced(DeclRefExpr *E, const Expr *Base) {
      OdrUse = false;
  if (auto *FD = dyn_cast<FunctionDecl>(E->getDecl()))
    if (!isConstantEvaluated() && FD->isConsteval() &&
        !RebuildingImmediateInvocation)
    if (!isUnevaluatedContext() && !isConstantEvaluated() &&
        FD->isConsteval() && !RebuildingImmediateInvocation)
      ExprEvalContexts.back().ReferenceToConsteval.insert(E);
  MarkExprReferenced(*this, E->getLocation(), E->getDecl(), E, OdrUse,
                     RefsMinusAssignments);
+32 −1
Original line number Diff line number Diff line
// RUN: %clang_cc1 -fsyntax-only -verify %s
// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify %s

// C++ [basic.def.odr]p2:
//   An expression is potentially evaluated unless it [...] is the
@@ -34,3 +35,33 @@ void test(X<Poly> xp, X<Poly, Poly&> xpr, X<NonPoly> xnp, X<NonPoly, NonPoly&> x
  // Triggers an error (as it should);
  xpr.g(Poly()); // expected-note{{instantiation of member function}}
}

#if __cplusplus >= 202002L

namespace unevaluated {

struct S {
  void f();
};
struct T {
  virtual void f();
};

consteval S *null_s() { return nullptr; }
consteval S *make_s() { return new S; }
consteval T *null_t() { return nullptr; }
consteval T *make_t() { return new T; } // #alloc

void func() {
  (void)typeid(*null_s());
  (void)typeid(*make_s());
  (void)typeid(*null_t()); // expected-warning {{expression with side effects will be evaluated despite being used as an operand to 'typeid'}}
  (void)typeid(*make_t()); // expected-error {{call to consteval function 'unevaluated::make_t' is not a constant expression}} \
                              expected-note {{pointer to heap-allocated object is not a constant expression}} \
                              expected-note@#alloc {{heap allocation performed here}} \
                              expected-warning {{expression with side effects will be evaluated despite being used as an operand to 'typeid'}}
}

} // namespace unevaluated

#endif
+18 −0
Original line number Diff line number Diff line
@@ -594,3 +594,21 @@ void test() {
}

} // namespace special_ctor

namespace unevaluated {

template <typename T, typename U> struct is_same { static const bool value = false; };
template <typename T> struct is_same<T, T> { static const bool value = true; };

long f(); // expected-note {{declared here}}
auto consteval g(auto a) {
  return a;
}

auto e = g(f()); // expected-error {{is not a constant expression}}
                 // expected-note@-1 {{non-constexpr function 'f' cannot be used in a constant expression}}

using T = decltype(g(f()));
static_assert(is_same<long, T>::value);

} // namespace unevaluated
+2 −1
Original line number Diff line number Diff line
@@ -1105,10 +1105,11 @@ code. This issue is expected to be rectified soon.
    <tr>
      <td rowspan=2>Immediate functions (<tt>consteval</tt>)</td>
      <td><a href="https://wg21.link/p1073r3">P1073R3</a></td>
      <td rowspan=2 class="none" align="center">No</td>
      <td class="partial" align="center">Partial</td>
    </tr>
      <tr> <!-- from Prague -->
        <td><a href="https://wg21.link/p1937r2">P1937R2</a></td>
        <td class="unreleased" align="center">Clang 14</td>
      </tr>
    <tr>
      <td><tt>std::is_constant_evaluated</tt></td>