Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cl testing #91

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 6 additions & 10 deletions clif/backend/matcher.cc
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,6 @@
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"

#ifndef PYCLIF_LLVM_VERSION_MAJOR
#define PYCLIF_LLVM_VERSION_MAJOR LLVM_VERSION_MAJOR
#endif

#if PYCLIF_LLVM_VERSION_MAJOR > 16
#include "clang/Sema/EnterExpressionEvaluationContext.h"
#endif
Expand Down Expand Up @@ -2989,20 +2985,20 @@ const clang::FunctionDecl* ClifMatcher::SpecializeFunctionTemplate(
}

std::string ClifMatcher::TemplateDeductionResult(
Sema::TemplateDeductionResult specialized_result) const {
PYCLIF_CLANG_TEMPLATEDEDUCTIONRESULT_TYPE specialized_result) const {
switch (specialized_result) {
case Sema::TDK_Invalid:
case PYCLIF_CLANG_TEMPLATEDEDUCTIONRESULT_ENUM(Invalid):
return "The template function declaration was invalid.";
case Sema::TDK_InstantiationDepth:
case PYCLIF_CLANG_TEMPLATEDEDUCTIONRESULT_ENUM(InstantiationDepth):
return "Template argument deduction exceeded the maximum template "
"instantiation depth.";
case Sema::TDK_Incomplete:
case PYCLIF_CLANG_TEMPLATEDEDUCTIONRESULT_ENUM(Incomplete):
return "Template argument deduction did not deduce a value for every "
"template parameter.";
case Sema::TDK_Inconsistent:
case PYCLIF_CLANG_TEMPLATEDEDUCTIONRESULT_ENUM(Inconsistent):
return "Template argument deduction produced inconsistent deduced "
"values.";
case Sema::TDK_Underqualified:
case PYCLIF_CLANG_TEMPLATEDEDUCTIONRESULT_ENUM(Underqualified):
return "Template argument deduction failed due to inconsistent "
"cv-qualifiers.";
default:
Expand Down
16 changes: 15 additions & 1 deletion clif/backend/matcher.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@
#include "clif/protos/ast.pb.h"
#include "gtest/gtest_prod.h" // Defines FRIEND_TEST.

#ifndef PYCLIF_LLVM_VERSION_MAJOR
#define PYCLIF_LLVM_VERSION_MAJOR LLVM_VERSION_MAJOR
#endif

namespace clif {

// ############################################################################
Expand Down Expand Up @@ -177,6 +181,16 @@ enum TypeMatchFlags : unsigned int {
class ClifError;
class ClifMatcherTest;

#if PYCLIF_LLVM_VERSION_MAJOR >= 19 // llvm/llvm-project#81398
#define PYCLIF_CLANG_TEMPLATEDEDUCTIONRESULT_TYPE clang::TemplateDeductionResult
#define PYCLIF_CLANG_TEMPLATEDEDUCTIONRESULT_ENUM(Name) \
clang::TemplateDeductionResult::Name
#else
#define PYCLIF_CLANG_TEMPLATEDEDUCTIONRESULT_TYPE \
clang::Sema::TemplateDeductionResult
#define PYCLIF_CLANG_TEMPLATEDEDUCTIONRESULT_ENUM(Name) Sema::TDK_##Name
#endif

class ClifMatcher {
friend class ClifMatcherTest;
public:
Expand Down Expand Up @@ -402,7 +416,7 @@ class ClifMatcher {

// Transform template type deduction error codes into error messages.
std::string TemplateDeductionResult(
clang::Sema::TemplateDeductionResult specialized_result) const;
PYCLIF_CLANG_TEMPLATEDEDUCTIONRESULT_TYPE specialized_result) const;

// Add the class type as the first parameter to a function.
void AdjustForNonClassMethods(protos::FuncDecl* clif_func_decl) const;
Expand Down
6 changes: 5 additions & 1 deletion clif/pybind11/classes.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@

I = utils.I

_USE_PYTYPE_TYPE_AS_METACLASS = True

_KNOWN_TYPES_WITH_MULTIPLE_INHERITANCE = {
'::borg::Config': ['::borg::ConfigArgs']
}
Expand Down Expand Up @@ -100,6 +102,8 @@ def generate_from(
base.cpp_canonical_type in codegen_info.dynamic_attr_types):
enable_instance_dict = True
break
if _USE_PYTYPE_TYPE_AS_METACLASS:
definition += ', py::metaclass((PyObject*) &PyType_Type)'
definition += ', py::release_gil_before_calling_cpp_dtor()'
if mi_bases:
definition += ', py::multiple_inheritance()'
Expand All @@ -117,7 +121,7 @@ def generate_from(
for member in class_decl.members:
if member.decltype == ast_pb2.Decl.Type.CONST:
for s in consts.generate_from(class_name, member.const):
yield I + I + s
yield I + s
elif member.decltype == ast_pb2.Decl.Type.FUNC:
if member.func.name.native in ('__reduce__', '__reduce_ex__'):
reduce_or_reduce_ex_defined = True
Expand Down
23 changes: 23 additions & 0 deletions clif/python/BUILD
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# CLIF python frontend

load("@clif_python_deps//:requirements.bzl", "requirement")
load("//devtools/clif/python:clif_build_rule.bzl", "py_clif_cc")
load("//third_party/bazel_rules/rules_python/python:py_test.bzl", "py_test")

package(
Expand Down Expand Up @@ -412,3 +413,25 @@ py_library(
srcs_version = "PY2AND3",
visibility = ["//visibility:public"],
)

cc_library(
name = "meta_ext_lib",
hdrs = ["meta_ext.h"],
)

py_clif_cc(
name = "_meta_ext",
srcs = ["meta_ext.clif"],
deps = [
":meta_ext_lib",
],
)

py_library(
name = "abc_utils",
srcs = ["abc_utils.py"],
visibility = ["//visibility:public"],
deps = [
":_meta_ext",
],
)
1 change: 1 addition & 0 deletions clif/python/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ target_link_libraries(proto_util_cc PRIVATE
${PYTHON_LIBRARIES}
)

add_py_library(abc_utils abc_utils.py)
add_py_library(callback_exception_guard callback_exception_guard.py)
add_py_library(type_customization type_customization.py)
add_py_library(postproc postproc.py)
Expand Down
24 changes: 24 additions & 0 deletions clif/python/abc_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
"""PyCLIF-pybind11 abc compatibility (in particular abc.ABCMeta).

This is for compatibility between the "default pybind11 metaclass"
(which is a custom metaclass) and https://docs.python.org/3/library/abc.html.

For background see:

* Description of https://github.com/pybind/pybind11/pull/5015

* Corresponding tests in clif/testing/python/classes_test.py
"""

import abc
import typing

PyCLIFMeta = type


if typing.TYPE_CHECKING:
PyCLIFABCMeta = abc.ABCMeta
else:

class PyCLIFABCMeta(abc.ABCMeta, PyCLIFMeta):
pass
4 changes: 4 additions & 0 deletions clif/python/meta_ext.clif
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
from "clif/python/meta_ext.h":
namespace `clif_meta_ext`:
class empty:
pass
10 changes: 10 additions & 0 deletions clif/python/meta_ext.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#ifndef CLIF_PYTHON_META_EXT_H_
#define CLIF_PYTHON_META_EXT_H_

namespace clif_meta_ext {

struct empty {};

} // namespace clif_meta_ext

#endif // CLIF_PYTHON_META_EXT_H_
4 changes: 2 additions & 2 deletions clif/python/primer.md
Original file line number Diff line number Diff line change
Expand Up @@ -713,8 +713,8 @@ of the return values as positional arguments. Whatever it returns becomes the
actual return value.

Some commonly needed post-processors have been provided in the above imported
library with CLIF. You can also
provide your own Python post-processor library.
library with CLIF.
You can also provide your own Python post-processor library.

## Naming Rules in CLIF Files {#naming_rules}

Expand Down
2 changes: 0 additions & 2 deletions clif/python/types.cc
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,6 @@ bool Clif_PyObjAs(PyObject* py, long* c) { //NOLINT: runtime/int
}

// int64
#ifdef HAVE_LONG_LONG
bool Clif_PyObjAs(PyObject* py, long long* c) { //NOLINT: runtime/int
CHECK(c != nullptr);
if (!PyLong_Check(py)) {
Expand Down Expand Up @@ -270,7 +269,6 @@ bool Clif_PyObjAs(PyObject* py, absl::uint128* c) { // NOLINT: runtime/int
}
return !PyErr_Occurred();
}
#endif // HAVE_LONG_LONG

#ifdef ABSL_HAVE_INTRINSIC_INT128
bool Clif_PyObjAs(PyObject* py, __int128* c) {
Expand Down
4 changes: 0 additions & 4 deletions clif/python/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,6 @@ inline PyObject* Clif_PyObjFrom(unsigned long c, // NOLINT runtime/int
return pc.Apply(PyLong_FromSize_t(c));
}
// CLIF use `int64` as int64
#ifdef HAVE_LONG_LONG
inline PyObject* Clif_PyObjFrom(long long c, // NOLINT runtime/int
const py::PostConv& pc) {
return pc.Apply(PyLong_FromLongLong(c));
Expand All @@ -128,7 +127,6 @@ inline PyObject* Clif_PyObjFrom(absl::uint128 c, const py::PostConv& pc) {
auto lo = PyLong_FromUnsignedLongLong(absl::Uint128Low64(c));
return pc.Apply(PyNumber_Add(hi, lo));
}
#endif

#ifdef ABSL_HAVE_INTRINSIC_INT128
// CLIF use2 `__int128` as int
Expand Down Expand Up @@ -195,12 +193,10 @@ bool Clif_PyObjAs(PyObject*, unsigned char*);
bool Clif_PyObjAs(PyObject*, unsigned short*); // NOLINT runtime/int
bool Clif_PyObjAs(PyObject*, unsigned int*);
bool Clif_PyObjAs(PyObject*, unsigned long*); // NOLINT runtime/int
#ifdef HAVE_LONG_LONG
bool Clif_PyObjAs(PyObject*, unsigned long long*); // NOLINT runtime/int
bool Clif_PyObjAs(PyObject*, long long*); // NOLINT runtime/int
bool Clif_PyObjAs(PyObject*, absl::int128*); // NOLINT runtime/int
bool Clif_PyObjAs(PyObject*, absl::uint128*); // NOLINT runtime/int
#endif
#ifdef ABSL_HAVE_INTRINSIC_INT128
bool Clif_PyObjAs(PyObject*, __int128*);
bool Clif_PyObjAs(PyObject*, unsigned __int128*);
Expand Down
4 changes: 3 additions & 1 deletion clif/testing/python/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,9 @@ add_pyclif_library_for_test(call_method call_method.clif)

add_pyclif_library_for_test(circular circular.clif)

add_pyclif_library_for_test(classes classes.clif)
add_pyclif_library_for_test(classes classes.clif
PY_DEPS clif_python_abc_utils
)

add_pyclif_library_for_test(class_module_attr class_module_attr.clif)

Expand Down
52 changes: 52 additions & 0 deletions clif/testing/python/classes_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,13 @@

"""Tests for clif.testing.python.classes."""

import abc
from unittest import mock

from absl.testing import absltest
from absl.testing import parameterized

from clif.python import abc_utils
from clif.testing.python import classes


Expand All @@ -35,6 +37,20 @@ def testKlass(self):
# AttributeError on CPython; TypeError on PyPy.
with self.assertRaises((AttributeError, TypeError)):
k.i2 = 0
self.assertEqual(classes.Klass.C, 1)
self.assertEqual(k.C, 1)
with self.assertRaisesRegex(AttributeError, 'read-only'):
k.C = 0

# UNDESIRABLE but long established behavior.
classes.Klass.C = 0 # C++ const but not read-only in Python.
self.assertEqual(classes.Klass.C, 0)
self.assertEqual(k.C, 0)
# Restore original value, to minimize the potential for surprises,
# just in case.
classes.Klass.C = 1
self.assertEqual(classes.Klass.C, 1)
self.assertEqual(k.C, 1)

def testMockIsRejected(self):
k_inst = classes.Klass(3)
Expand Down Expand Up @@ -212,6 +228,42 @@ def testNestedUnproperty(self, attr, expected, new_value, new_expected):
ret = getattr(obj, getter)()
self.assertEqual(ret, new_expected)

def testABCMeta(self):
# Purely to help the linter.
ABCMeta = abc.ABCMeta # pylint: disable=unused-variable

if abc_utils.PyCLIFMeta is type:

class KlassABCMeta(classes.Klass, metaclass=ABCMeta):
pass

self.assertEqual(type(classes.Klass).__name__, 'type')
km = KlassABCMeta(5)
self.assertEqual(km.i, 5)

else:
self.assertEqual(classes.__pyclif_codegen_mode__, 'pybind11')
with self.assertRaisesRegex(TypeError, 'metaclass conflict'):

class KlassABCMeta(classes.Klass, metaclass=ABCMeta):
pass

def testPyCLIFABCMeta(self):
# Purely to help the linter.
PyCLIFABCMeta = abc_utils.PyCLIFABCMeta # pylint: disable=unused-variable,invalid-name

class KlassPyCLIFABCMeta(classes.Klass, metaclass=PyCLIFABCMeta):
pass

if abc_utils.PyCLIFMeta is type:
expected_type_name = 'type'
else:
self.assertEqual(classes.__pyclif_codegen_mode__, 'pybind11')
expected_type_name = 'pybind11_type'
self.assertEqual(type(classes.Klass).__name__, expected_type_name)
km = KlassPyCLIFABCMeta(5)
self.assertEqual(km.i, 5)


if __name__ == '__main__':
absltest.main()