@@ -1850,6 +1850,7 @@ static Object doPointer(GraalHPyContext hpyContext, PythonNativeObject n, @Suppr
18501850 * int basicsize;
18511851 * int itemsize;
18521852 * unsigned int flags;
1853+ * int legacy;
18531854 * void *legacy_slots;
18541855 * HPyDef **defines;
18551856 * const char *doc;
@@ -1881,6 +1882,7 @@ static Object doGeneric(GraalHPyContext context, Object typeSpec, Object typeSpe
18811882 @ Cached HPyCreateGetSetDescriptorNode createGetSetDescriptorNode ,
18821883 @ Cached GetSuperClassNode getSuperClassNode ,
18831884 @ Cached IsSameTypeNode isSameTypeNode ,
1885+ @ Cached ReadAttributeFromObjectNode readHPyTypeFlagsNode ,
18841886 @ Cached (parameters = "New" ) LookupCallableSlotInMRONode lookupNewNode ,
18851887 @ Cached HPyAsPythonObjectNode hPyAsPythonObjectNode ,
18861888 @ Cached PRaiseNode raiseNode ) {
@@ -1930,6 +1932,13 @@ static Object doGeneric(GraalHPyContext context, Object typeSpec, Object typeSpe
19301932 throw raiseNode .raise (TypeError , "HPy_TPFLAGS_INTERNAL_PURE should not be used directly, set .legacy=true instead" );
19311933 }
19321934
1935+ long legacy = castToLong (valueLib , ptrLib .readMember (typeSpec , "legacy" ));
1936+ if (legacy != 0 ) {
1937+ flags &= ~GraalHPyDef .HPy_TPFLAGS_INTERNAL_PURE ;
1938+ } else {
1939+ flags |= GraalHPyDef .HPy_TPFLAGS_INTERNAL_PURE ;
1940+ }
1941+
19331942 long basicSize = castToLong (valueLib , ptrLib .readMember (typeSpec , "basicsize" ));
19341943 long itemSize = castToLong (valueLib , ptrLib .readMember (typeSpec , "itemsize" ));
19351944 writeAttributeToObjectNode .execute (newType , GraalHPyDef .TYPE_HPY_ITEMSIZE , itemSize );
@@ -2007,10 +2016,10 @@ static Object doGeneric(GraalHPyContext context, Object typeSpec, Object typeSpe
20072016 * constructors won't usually do that. So, we compute the constructor here and
20082017 * decorate it.
20092018 */
2019+ Object baseClass = getSuperClassNode .execute (newType );
20102020 if (basicSize > 0 && !seenNew ) {
20112021 Object inheritedConstructor = null ;
20122022
2013- Object baseClass = getSuperClassNode .execute (newType );
20142023 if (!isSameTypeNode .execute (baseClass , PythonBuiltinClassType .PythonObject )) {
20152024 // Lookup the inherited constructor and pass it to the HPy decorator.
20162025 inheritedConstructor = lookupNewNode .execute (baseClass );
@@ -2020,6 +2029,15 @@ static Object doGeneric(GraalHPyContext context, Object typeSpec, Object typeSpe
20202029 writeAttributeToObjectNode .execute (newType , SpecialMethodNames .__NEW__ , constructorDecorator );
20212030 }
20222031
2032+ long baseFlags ;
2033+ if (baseClass instanceof PythonClass ) {
2034+ baseFlags = ((PythonClass ) baseClass ).flags ;
2035+ } else {
2036+ Object baseFlagsObj = readHPyTypeFlagsNode .execute (baseClass , GraalHPyDef .TYPE_HPY_FLAGS );
2037+ baseFlags = baseFlagsObj != PNone .NO_VALUE ? (long ) baseFlagsObj : 0 ;
2038+ }
2039+ checkInheritanceConstraints (flags , baseFlags , raiseNode );
2040+
20232041 return newType ;
20242042 } catch (CannotCastException | InteropException e ) {
20252043 throw raiseNode .raise (SystemError , "Could not create type from spec because: %m" , e );
@@ -2100,6 +2118,24 @@ private static String[] splitName(String specName) {
21002118 return new String []{null , specName };
21012119 }
21022120
2121+ private static void checkInheritanceConstraints (long flags , long baseFlags , PRaiseNode raiseNode ) {
2122+ boolean isPure = (flags & GraalHPyDef .HPy_TPFLAGS_INTERNAL_PURE ) != 0 ;
2123+ boolean isBasePure = (baseFlags & GraalHPyDef .HPy_TPFLAGS_INTERNAL_PURE ) != 0 ;
2124+ // Pure types may inherit from:
2125+ //
2126+ // * pure types, or
2127+ // * PyBaseObject_Type, or
2128+ // * other builtin or legacy types as long as long as they do not
2129+ // access the struct layout (e.g. by using HPy_AsStruct or defining
2130+ // a deallocator with HPy_tp_destroy).
2131+ //
2132+ // It would be nice to relax these restrictions or check them here.
2133+ // See https://github.com/hpyproject/hpy/issues/169 for details.
2134+ if (!isPure && isBasePure ) {
2135+ throw raiseNode .raise (TypeError , "A legacy type should not inherit its memory layout from a pure type" );
2136+ }
2137+ }
2138+
21032139 private static long castToLong (InteropLibrary lib , Object value ) throws OverflowException {
21042140 if (lib .fitsInLong (value )) {
21052141 try {
0 commit comments