Author: Timm Bäder Date: 2023-09-05T12:21:26+02:00 New Revision: 5704dde307359e9155e2fcd99c413c0cf932aa13
URL: https://github.com/llvm/llvm-project/commit/5704dde307359e9155e2fcd99c413c0cf932aa13 DIFF: https://github.com/llvm/llvm-project/commit/5704dde307359e9155e2fcd99c413c0cf932aa13.diff LOG: [clang][Interp] Reject calling virtual constexpr functions in pre-c++20 Differential Revision: https://reviews.llvm.org/D157619 Added: Modified: 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 Removed: ################################################################################ diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/ByteCodeExprGen.cpp index d13a805f0714ff..244290dc6393f4 100644 --- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp +++ b/clang/lib/AST/Interp/ByteCodeExprGen.cpp @@ -1816,24 +1816,7 @@ Record *ByteCodeExprGen<Emitter>::getRecord(const RecordDecl *RD) { 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> diff --git a/clang/lib/AST/Interp/Context.cpp b/clang/lib/AST/Interp/Context.cpp index 6e0d949457d673..1a732b6c1a092a 100644 --- a/clang/lib/AST/Interp/Context.cpp +++ b/clang/lib/AST/Interp/Context.cpp @@ -210,3 +210,24 @@ Context::getOverridingFunction(const CXXRecordDecl *DynamicDecl, "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; +} diff --git a/clang/lib/AST/Interp/Context.h b/clang/lib/AST/Interp/Context.h index f5dc80af757a14..617fbaa928f40e 100644 --- a/clang/lib/AST/Interp/Context.h +++ b/clang/lib/AST/Interp/Context.h @@ -72,6 +72,9 @@ class Context final { 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) { diff --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h index b87a5c1cbd0e48..5006f72fe7237f 100644 --- a/clang/lib/AST/Interp/Interp.h +++ b/clang/lib/AST/Interp/Interp.h @@ -1765,7 +1765,15 @@ inline bool CallVirt(InterpState &S, CodePtr OpPC, const Function *Func) { 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(); diff --git a/clang/test/AST/Interp/records.cpp b/clang/test/AST/Interp/records.cpp index 7976f2d91e99c0..4e39ded41ad25f 100644 --- a/clang/test/AST/Interp/records.cpp +++ b/clang/test/AST/Interp/records.cpp @@ -871,6 +871,35 @@ namespace VirtualFunctionPointers { }; #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; _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits