Author: Timm Bäder Date: 2023-04-27T12:33:28+02:00 New Revision: f8a9c55bef380a592c4588025f8b6ca4dfc94c47
URL: https://github.com/llvm/llvm-project/commit/f8a9c55bef380a592c4588025f8b6ca4dfc94c47 DIFF: https://github.com/llvm/llvm-project/commit/f8a9c55bef380a592c4588025f8b6ca4dfc94c47.diff LOG: [clang][Interp] Emit diagnostic when comparing function pointers Function pointers can be compared for (in)equality but, but LE, GE, LT, and GT opcodes should emit an error and abort. Differential Revision: https://reviews.llvm.org/D149154 Added: Modified: clang/lib/AST/Interp/FunctionPointer.h clang/lib/AST/Interp/Interp.h clang/lib/AST/Interp/Opcodes.td clang/test/AST/Interp/functions.cpp Removed: ################################################################################ diff --git a/clang/lib/AST/Interp/FunctionPointer.h b/clang/lib/AST/Interp/FunctionPointer.h index 2d449bdb031d..20d4d7793185 100644 --- a/clang/lib/AST/Interp/FunctionPointer.h +++ b/clang/lib/AST/Interp/FunctionPointer.h @@ -8,6 +8,7 @@ #include "clang/AST/APValue.h" namespace clang { +class ASTContext; namespace interp { class FunctionPointer final { @@ -38,6 +39,13 @@ class FunctionPointer final { OS << ")"; } + std::string toDiagnosticString(const ASTContext &Ctx) const { + if (!Func) + return "nullptr"; + + return toAPValue().getAsString(Ctx, Func->getDecl()->getType()); + } + ComparisonCategoryResult compare(const FunctionPointer &RHS) const { if (Func == RHS.Func) return ComparisonCategoryResult::Equal; diff --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h index 7b80bb964991..d751ba021b11 100644 --- a/clang/lib/AST/Interp/Interp.h +++ b/clang/lib/AST/Interp/Interp.h @@ -574,6 +574,29 @@ bool CmpHelperEQ(InterpState &S, CodePtr OpPC, CompareFn Fn) { return CmpHelper<T>(S, OpPC, Fn); } +/// Function pointers cannot be compared in an ordered way. +template <> +inline bool CmpHelper<FunctionPointer>(InterpState &S, CodePtr OpPC, + CompareFn Fn) { + const auto &RHS = S.Stk.pop<FunctionPointer>(); + const auto &LHS = S.Stk.pop<FunctionPointer>(); + + const SourceInfo &Loc = S.Current->getSource(OpPC); + S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_unspecified) + << LHS.toDiagnosticString(S.getCtx()) + << RHS.toDiagnosticString(S.getCtx()); + return false; +} + +template <> +inline bool CmpHelperEQ<FunctionPointer>(InterpState &S, CodePtr OpPC, + CompareFn Fn) { + const auto &RHS = S.Stk.pop<FunctionPointer>(); + const auto &LHS = S.Stk.pop<FunctionPointer>(); + S.Stk.push<Boolean>(Boolean::from(Fn(LHS.compare(RHS)))); + return true; +} + template <> inline bool CmpHelper<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) { using BoolT = PrimConv<PT_Bool>::T; diff --git a/clang/lib/AST/Interp/Opcodes.td b/clang/lib/AST/Interp/Opcodes.td index ed0774a78833..717c4629fcc3 100644 --- a/clang/lib/AST/Interp/Opcodes.td +++ b/clang/lib/AST/Interp/Opcodes.td @@ -94,7 +94,7 @@ def AllTypeClass : TypeClass { } def ComparableTypeClass : TypeClass { - let Types = !listconcat(AluTypeClass.Types, [Ptr], [Float]); + let Types = !listconcat(AluTypeClass.Types, [Ptr], [Float], [FnPtr]); } class SingletonTypeClass<Type Ty> : TypeClass { diff --git a/clang/test/AST/Interp/functions.cpp b/clang/test/AST/Interp/functions.cpp index a8681aae0d58..5bb48ffc54dd 100644 --- a/clang/test/AST/Interp/functions.cpp +++ b/clang/test/AST/Interp/functions.cpp @@ -178,6 +178,31 @@ namespace FunctionReturnType { static_assert(s.fp == nullptr, ""); // zero-initialized function pointer. } +namespace Comparison { + void f(), g(); + constexpr void (*pf)() = &f, (*pg)() = &g; + + constexpr bool u13 = pf < pg; // ref-warning {{ordered comparison of function pointers}} \ + // ref-error {{must be initialized by a constant expression}} \ + // ref-note {{comparison between '&f' and '&g' has unspecified value}} \ + // expected-warning {{ordered comparison of function pointers}} \ + // expected-error {{must be initialized by a constant expression}} \ + // expected-note {{comparison between '&f' and '&g' has unspecified value}} + + constexpr bool u14 = pf < (void(*)())nullptr; // ref-warning {{ordered comparison of function pointers}} \ + // ref-error {{must be initialized by a constant expression}} \ + // ref-note {{comparison between '&f' and 'nullptr' has unspecified value}} \ + // expected-warning {{ordered comparison of function pointers}} \ + // expected-error {{must be initialized by a constant expression}} \ + // expected-note {{comparison between '&f' and 'nullptr' has unspecified value}} + + + + static_assert(pf != pg, ""); + static_assert(pf == &f, ""); + static_assert(pg == &g, ""); +} + } struct F { _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits