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 cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits