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

Reply via email to