tbaeder created this revision.
tbaeder added reviewers: aaron.ballman, erichkeane, shafik, cor3ntin.
Herald added a project: All.
tbaeder requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.
Create a new `getOrCreateFunction()` in `Context`, so we can lazily compile
functions when invoking them in `CallVirt`. This was necessary in the added
test case for example.
Also, reject calling virtual constexpr functions in pre-c++20.
Repository:
rG LLVM Github Monorepo
https://reviews.llvm.org/D157619
Files:
clang/lib/AST/Interp/ByteCodeExprGen.cpp
clang/lib/AST/Interp/Context.cpp
clang/lib/AST/Interp/Context.h
clang/lib/AST/Interp/Interp.h
clang/test/AST/Interp/records.cpp
Index: clang/test/AST/Interp/records.cpp
===================================================================
--- clang/test/AST/Interp/records.cpp
+++ clang/test/AST/Interp/records.cpp
@@ -857,6 +857,35 @@
};
#endif
+#if __cplusplus < 202002L
+namespace VirtualFromBase {
+ struct S1 {
+ virtual int f() const;
+ };
+ struct S2 {
+ virtual int f();
+ };
+ template <typename T> struct X : T {
+ constexpr X() {}
+ double d = 0.0;
+ constexpr int f() { return sizeof(T); }
+ };
+
+ // Non-virtual f(), OK.
+ constexpr X<X<S1>> xxs1;
+ constexpr X<S1> *p = const_cast<X<X<S1>>*>(&xxs1);
+ static_assert(p->f() == sizeof(S1), "");
+
+ // Virtual f(), not OK.
+ constexpr X<X<S2>> xxs2;
+ constexpr X<S2> *q = const_cast<X<X<S2>>*>(&xxs2);
+ static_assert(q->f() == sizeof(X<S2>), ""); // ref-error {{not an integral constant expression}} \
+ // ref-note {{cannot evaluate call to virtual function}} \
+ // expected-error {{not an integral constant expression}} \
+ // expected-note {{cannot evaluate call to virtual function}}
+}
+#endif
+
namespace CompositeDefaultArgs {
struct Foo {
int a;
Index: clang/lib/AST/Interp/Interp.h
===================================================================
--- clang/lib/AST/Interp/Interp.h
+++ clang/lib/AST/Interp/Interp.h
@@ -1835,7 +1835,15 @@
DynamicDecl, StaticDecl, InitialFunction);
if (Overrider != InitialFunction) {
- Func = S.P.getFunction(Overrider);
+ // DR1872: An instantiated virtual constexpr function can't be called in a
+ // constant expression (prior to C++20). We can still constant-fold such a
+ // call.
+ if (!S.getLangOpts().CPlusPlus20 && Overrider->isVirtual()) {
+ const Expr *E = S.Current->getExpr(OpPC);
+ S.CCEDiag(E, diag::note_constexpr_virtual_call) << E->getSourceRange();
+ }
+
+ Func = S.getContext().getOrCreateFunction(Overrider);
const CXXRecordDecl *ThisFieldDecl =
ThisPtr.getFieldDesc()->getType()->getAsCXXRecordDecl();
Index: clang/lib/AST/Interp/Context.h
===================================================================
--- clang/lib/AST/Interp/Context.h
+++ clang/lib/AST/Interp/Context.h
@@ -72,6 +72,9 @@
getOverridingFunction(const CXXRecordDecl *DynamicDecl,
const CXXRecordDecl *StaticDecl,
const CXXMethodDecl *InitialFunction) const;
+
+ const Function *getOrCreateFunction(const FunctionDecl *FD);
+
/// Returns whether we should create a global variable for the
/// given ValueDecl.
static bool shouldBeGloballyIndexed(const ValueDecl *VD) {
Index: clang/lib/AST/Interp/Context.cpp
===================================================================
--- clang/lib/AST/Interp/Context.cpp
+++ clang/lib/AST/Interp/Context.cpp
@@ -215,3 +215,24 @@
"Couldn't find an overriding function in the class hierarchy?");
return nullptr;
}
+
+const Function *Context::getOrCreateFunction(const FunctionDecl *FD) {
+ assert(FD);
+ const Function *Func = P->getFunction(FD);
+ bool IsBeingCompiled = Func && !Func->isFullyCompiled();
+ bool WasNotDefined = Func && !Func->isConstexpr() && !Func->hasBody();
+
+ if (IsBeingCompiled)
+ return Func;
+
+ if (!Func || WasNotDefined) {
+ if (auto R = ByteCodeStmtGen<ByteCodeEmitter>(*this, *P).compileFunc(FD))
+ Func = *R;
+ else {
+ llvm::consumeError(R.takeError());
+ return nullptr;
+ }
+ }
+
+ return Func;
+}
Index: clang/lib/AST/Interp/ByteCodeExprGen.cpp
===================================================================
--- clang/lib/AST/Interp/ByteCodeExprGen.cpp
+++ clang/lib/AST/Interp/ByteCodeExprGen.cpp
@@ -2063,24 +2063,7 @@
template <class Emitter>
const Function *ByteCodeExprGen<Emitter>::getFunction(const FunctionDecl *FD) {
- assert(FD);
- const Function *Func = P.getFunction(FD);
- bool IsBeingCompiled = Func && !Func->isFullyCompiled();
- bool WasNotDefined = Func && !Func->isConstexpr() && !Func->hasBody();
-
- if (IsBeingCompiled)
- return Func;
-
- if (!Func || WasNotDefined) {
- if (auto R = ByteCodeStmtGen<ByteCodeEmitter>(Ctx, P).compileFunc(FD))
- Func = *R;
- else {
- llvm::consumeError(R.takeError());
- return nullptr;
- }
- }
-
- return Func;
+ return Ctx.getOrCreateFunction(FD);
}
template <class Emitter>
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits