Skip to content

Commit 131b462

Browse files
cor3ntinAaronBallman
authored andcommitted
Implement P1937 consteval in unevaluated contexts
In an unevaluated contexts, consteval functions should not be immediately evaluated.
1 parent 3c8e94b commit 131b462

File tree

4 files changed

+56
-5
lines changed

4 files changed

+56
-5
lines changed

clang/lib/Sema/SemaExpr.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16641,7 +16641,8 @@ void Sema::CheckUnusedVolatileAssignment(Expr *E) {
1664116641
}
1664216642

1664316643
ExprResult Sema::CheckForImmediateInvocation(ExprResult E, FunctionDecl *Decl) {
16644-
if (!E.isUsable() || !Decl || !Decl->isConsteval() || isConstantEvaluated() ||
16644+
if (isUnevaluatedContext() || !E.isUsable() || !Decl ||
16645+
!Decl->isConsteval() || isConstantEvaluated() ||
1664516646
RebuildingImmediateInvocation)
1664616647
return E;
1664716648

@@ -18758,8 +18759,8 @@ void Sema::MarkDeclRefReferenced(DeclRefExpr *E, const Expr *Base) {
1875818759
OdrUse = false;
1875918760

1876018761
if (auto *FD = dyn_cast<FunctionDecl>(E->getDecl()))
18761-
if (!isConstantEvaluated() && FD->isConsteval() &&
18762-
!RebuildingImmediateInvocation)
18762+
if (!isUnevaluatedContext() && !isConstantEvaluated() &&
18763+
FD->isConsteval() && !RebuildingImmediateInvocation)
1876318764
ExprEvalContexts.back().ReferenceToConsteval.insert(E);
1876418765
MarkExprReferenced(*this, E->getLocation(), E->getDecl(), E, OdrUse,
1876518766
RefsMinusAssignments);

clang/test/CXX/basic/basic.def.odr/p2-typeid.cpp

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
// RUN: %clang_cc1 -fsyntax-only -verify %s
2+
// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify %s
23

34
// C++ [basic.def.odr]p2:
45
// An expression is potentially evaluated unless it [...] is the
@@ -16,7 +17,7 @@ struct Poly {
1617

1718
struct NonPoly { };
1819

19-
template<typename T, typename Result = T>
20+
template<typename T, typename Result = T>
2021
struct X {
2122
Result f(T t) { return t + t; } // expected-error{{invalid operands}}
2223

@@ -34,3 +35,33 @@ void test(X<Poly> xp, X<Poly, Poly&> xpr, X<NonPoly> xnp, X<NonPoly, NonPoly&> x
3435
// Triggers an error (as it should);
3536
xpr.g(Poly()); // expected-note{{instantiation of member function}}
3637
}
38+
39+
#if __cplusplus >= 202002L
40+
41+
namespace unevaluated {
42+
43+
struct S {
44+
void f();
45+
};
46+
struct T {
47+
virtual void f();
48+
};
49+
50+
consteval S *null_s() { return nullptr; }
51+
consteval S *make_s() { return new S; }
52+
consteval T *null_t() { return nullptr; }
53+
consteval T *make_t() { return new T; } // #alloc
54+
55+
void func() {
56+
(void)typeid(*null_s());
57+
(void)typeid(*make_s());
58+
(void)typeid(*null_t()); // expected-warning {{expression with side effects will be evaluated despite being used as an operand to 'typeid'}}
59+
(void)typeid(*make_t()); // expected-error {{call to consteval function 'unevaluated::make_t' is not a constant expression}} \
60+
expected-note {{pointer to heap-allocated object is not a constant expression}} \
61+
expected-note@#alloc {{heap allocation performed here}} \
62+
expected-warning {{expression with side effects will be evaluated despite being used as an operand to 'typeid'}}
63+
}
64+
65+
} // namespace unevaluated
66+
67+
#endif

clang/test/SemaCXX/cxx2a-consteval.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -594,3 +594,21 @@ void test() {
594594
}
595595

596596
} // namespace special_ctor
597+
598+
namespace unevaluated {
599+
600+
template <typename T, typename U> struct is_same { static const bool value = false; };
601+
template <typename T> struct is_same<T, T> { static const bool value = true; };
602+
603+
long f(); // expected-note {{declared here}}
604+
auto consteval g(auto a) {
605+
return a;
606+
}
607+
608+
auto e = g(f()); // expected-error {{is not a constant expression}}
609+
// expected-note@-1 {{non-constexpr function 'f' cannot be used in a constant expression}}
610+
611+
using T = decltype(g(f()));
612+
static_assert(is_same<long, T>::value);
613+
614+
} // namespace unevaluated

clang/www/cxx_status.html

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1105,10 +1105,11 @@ <h2 id="cxx20">C++20 implementation status</h2>
11051105
<tr>
11061106
<td rowspan=2>Immediate functions (<tt>consteval</tt>)</td>
11071107
<td><a href="https://wg21.link/p1073r3">P1073R3</a></td>
1108-
<td rowspan=2 class="none" align="center">No</td>
1108+
<td class="partial" align="center">Partial</td>
11091109
</tr>
11101110
<tr> <!-- from Prague -->
11111111
<td><a href="https://wg21.link/p1937r2">P1937R2</a></td>
1112+
<td class="unreleased" align="center">Clang 14</td>
11121113
</tr>
11131114
<tr>
11141115
<td><tt>std::is_constant_evaluated</tt></td>

0 commit comments

Comments
 (0)