mirror of
https://github.com/dart-lang/sdk
synced 2024-09-16 03:27:43 +00:00
[vm/ffi] Change Pointer.elementAt
and sizeOf
to use static type
This CL changes the semantics of `Pointer<T extends NativeType>.elementAt` and `sizeOf<T extends NativeType>` to use the compile-time `T` rather than the runtime `T`. Issue: https://github.com/dart-lang/sdk/issues/38721 TEST=tests/ffi/data_test.dart TEST=tests/ffi/sizeof_test.dart TEST=tests/ffi/structs_test.dart TEST=tests/ffi/vmspecific_static_checks_test.dart Change-Id: Ifb25a4bd66d50a385d3db6dec9213b96dff21722 Cq-Include-Trybots: luci.dart.try:vm-precomp-ffi-qemu-linux-release-arm-try,analyzer-analysis-server-linux-try,analyzer-linux-release-try,analyzer-nnbd-linux-release-try,front-end-linux-release-x64-try,front-end-nnbd-linux-release-x64-try,benchmark-linux-try,dart-sdk-linux-try,pkg-linux-release-try,vm-ffi-android-release-arm-try,vm-ffi-android-release-arm64-try Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/178200 Reviewed-by: Aske Simon Christensen <askesc@google.com>
This commit is contained in:
parent
f169abcee0
commit
3593de9179
|
@ -474,7 +474,6 @@ const List<ErrorCode> errorCodeValues = [
|
||||||
FfiCode.MUST_BE_A_NATIVE_FUNCTION_TYPE,
|
FfiCode.MUST_BE_A_NATIVE_FUNCTION_TYPE,
|
||||||
FfiCode.MUST_BE_A_SUBTYPE,
|
FfiCode.MUST_BE_A_SUBTYPE,
|
||||||
FfiCode.NON_CONSTANT_TYPE_ARGUMENT,
|
FfiCode.NON_CONSTANT_TYPE_ARGUMENT,
|
||||||
FfiCode.NON_CONSTANT_TYPE_ARGUMENT_WARNING,
|
|
||||||
FfiCode.NON_NATIVE_FUNCTION_TYPE_ARGUMENT_TO_POINTER,
|
FfiCode.NON_NATIVE_FUNCTION_TYPE_ARGUMENT_TO_POINTER,
|
||||||
FfiCode.NON_SIZED_TYPE_ARGUMENT,
|
FfiCode.NON_SIZED_TYPE_ARGUMENT,
|
||||||
FfiCode.SUBTYPE_OF_FFI_CLASS_IN_EXTENDS,
|
FfiCode.SUBTYPE_OF_FFI_CLASS_IN_EXTENDS,
|
||||||
|
|
|
@ -183,20 +183,6 @@ class FfiCode extends AnalyzerErrorCode {
|
||||||
"parameters are not constants.",
|
"parameters are not constants.",
|
||||||
correction: "Try changing the type argument to be a constant type.");
|
correction: "Try changing the type argument to be a constant type.");
|
||||||
|
|
||||||
/**
|
|
||||||
* Parameters:
|
|
||||||
* 0: the name of the function, method, or constructor having type arguments
|
|
||||||
*/
|
|
||||||
static const FfiCode NON_CONSTANT_TYPE_ARGUMENT_WARNING = FfiCode(
|
|
||||||
name: 'NON_CONSTANT_TYPE_ARGUMENT_WARNING',
|
|
||||||
message:
|
|
||||||
"Support for using non-constant type arguments '{0}' in this FFI API"
|
|
||||||
" is deprecated and will be removed in the next stable version of "
|
|
||||||
"Dart. Rewrite the code to ensure that type arguments are compile "
|
|
||||||
"time constants referring to a valid native type.",
|
|
||||||
correction: "Try changing the type argument to be a constant type.",
|
|
||||||
type: ErrorType.HINT);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parameters:
|
* Parameters:
|
||||||
* 0: the type that should be a valid dart:ffi native type.
|
* 0: the type that should be a valid dart:ffi native type.
|
||||||
|
|
|
@ -525,9 +525,7 @@ class FfiVerifier extends RecursiveAstVisitor<void> {
|
||||||
if (!_isValidFfiNativeType(T, allowVoid: true, allowEmptyStruct: true)) {
|
if (!_isValidFfiNativeType(T, allowVoid: true, allowEmptyStruct: true)) {
|
||||||
final AstNode errorNode = node;
|
final AstNode errorNode = node;
|
||||||
_errorReporter.reportErrorForNode(
|
_errorReporter.reportErrorForNode(
|
||||||
FfiCode.NON_CONSTANT_TYPE_ARGUMENT_WARNING,
|
FfiCode.NON_CONSTANT_TYPE_ARGUMENT, errorNode, ['elementAt']);
|
||||||
errorNode,
|
|
||||||
['elementAt']);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -703,7 +701,7 @@ class FfiVerifier extends RecursiveAstVisitor<void> {
|
||||||
if (!_isValidFfiNativeType(T, allowVoid: true, allowEmptyStruct: true)) {
|
if (!_isValidFfiNativeType(T, allowVoid: true, allowEmptyStruct: true)) {
|
||||||
final AstNode errorNode = node;
|
final AstNode errorNode = node;
|
||||||
_errorReporter.reportErrorForNode(
|
_errorReporter.reportErrorForNode(
|
||||||
FfiCode.NON_CONSTANT_TYPE_ARGUMENT_WARNING, errorNode, ['sizeOf']);
|
FfiCode.NON_CONSTANT_TYPE_ARGUMENT, errorNode, ['sizeOf']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -62,7 +62,6 @@ export '../fasta/fasta_codes.dart'
|
||||||
templateFfiFieldCyclic,
|
templateFfiFieldCyclic,
|
||||||
templateFfiFieldInitializer,
|
templateFfiFieldInitializer,
|
||||||
templateFfiFieldNoAnnotation,
|
templateFfiFieldNoAnnotation,
|
||||||
templateFfiNonConstantTypeArgumentWarning,
|
|
||||||
templateFfiNotStatic,
|
templateFfiNotStatic,
|
||||||
templateFfiStructGeneric,
|
templateFfiStructGeneric,
|
||||||
templateFfiTypeInvalid,
|
templateFfiTypeInvalid,
|
||||||
|
|
|
@ -915,35 +915,6 @@ Message _withArgumentsFfiExpectedNoExceptionalReturn(
|
||||||
arguments: {'type': _type});
|
arguments: {'type': _type});
|
||||||
}
|
}
|
||||||
|
|
||||||
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
|
|
||||||
const Template<Message Function(DartType _type, bool isNonNullableByDefault)>
|
|
||||||
templateFfiNonConstantTypeArgumentWarning = const Template<
|
|
||||||
Message Function(DartType _type, bool isNonNullableByDefault)>(
|
|
||||||
messageTemplate:
|
|
||||||
r"""Support for using non-constant type arguments '#type' in this FFI API is deprecated and will be removed in the next stable version of Dart. Rewrite the code to ensure that type arguments are compile time constants referring to a valid native type.""",
|
|
||||||
withArguments: _withArgumentsFfiNonConstantTypeArgumentWarning);
|
|
||||||
|
|
||||||
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
|
|
||||||
const Code<Message Function(DartType _type, bool isNonNullableByDefault)>
|
|
||||||
codeFfiNonConstantTypeArgumentWarning =
|
|
||||||
const Code<Message Function(DartType _type, bool isNonNullableByDefault)>(
|
|
||||||
"FfiNonConstantTypeArgumentWarning",
|
|
||||||
analyzerCodes: <String>["NON_CONSTANT_TYPE_ARGUMENT_WARNING"],
|
|
||||||
severity: Severity.info);
|
|
||||||
|
|
||||||
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
|
|
||||||
Message _withArgumentsFfiNonConstantTypeArgumentWarning(
|
|
||||||
DartType _type, bool isNonNullableByDefault) {
|
|
||||||
TypeLabeler labeler = new TypeLabeler(isNonNullableByDefault);
|
|
||||||
List<Object> typeParts = labeler.labelType(_type);
|
|
||||||
String type = typeParts.join();
|
|
||||||
return new Message(codeFfiNonConstantTypeArgumentWarning,
|
|
||||||
message:
|
|
||||||
"""Support for using non-constant type arguments '${type}' in this FFI API is deprecated and will be removed in the next stable version of Dart. Rewrite the code to ensure that type arguments are compile time constants referring to a valid native type.""" +
|
|
||||||
labeler.originMessages,
|
|
||||||
arguments: {'type': _type});
|
|
||||||
}
|
|
||||||
|
|
||||||
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
|
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
|
||||||
const Template<
|
const Template<
|
||||||
Message Function(
|
Message Function(
|
||||||
|
|
|
@ -4242,13 +4242,6 @@ FfiFieldCyclic:
|
||||||
#names
|
#names
|
||||||
external: test/ffi_test.dart
|
external: test/ffi_test.dart
|
||||||
|
|
||||||
FfiNonConstantTypeArgumentWarning:
|
|
||||||
# Used by dart:ffi
|
|
||||||
template: "Support for using non-constant type arguments '#type' in this FFI API is deprecated and will be removed in the next stable version of Dart. Rewrite the code to ensure that type arguments are compile time constants referring to a valid native type."
|
|
||||||
analyzerCode: NON_CONSTANT_TYPE_ARGUMENT_WARNING
|
|
||||||
severity: INFO
|
|
||||||
external: test/ffi_test.dart
|
|
||||||
|
|
||||||
FfiNotStatic:
|
FfiNotStatic:
|
||||||
# Used by dart:ffi
|
# Used by dart:ffi
|
||||||
template: "#name expects a static function as parameter. dart:ffi only supports calling static Dart functions from native code."
|
template: "#name expects a static function as parameter. dart:ffi only supports calling static Dart functions from native code."
|
||||||
|
|
|
@ -13,7 +13,6 @@ import 'package:front_end/src/api_unstable/vm.dart'
|
||||||
templateFfiExpectedExceptionalReturn,
|
templateFfiExpectedExceptionalReturn,
|
||||||
templateFfiExpectedNoExceptionalReturn,
|
templateFfiExpectedNoExceptionalReturn,
|
||||||
templateFfiExtendsOrImplementsSealedClass,
|
templateFfiExtendsOrImplementsSealedClass,
|
||||||
templateFfiNonConstantTypeArgumentWarning,
|
|
||||||
templateFfiNotStatic,
|
templateFfiNotStatic,
|
||||||
templateFfiTypeInvalid,
|
templateFfiTypeInvalid,
|
||||||
templateFfiTypeMismatch;
|
templateFfiTypeMismatch;
|
||||||
|
@ -189,7 +188,7 @@ class _FfiUseSiteTransformer extends FfiTransformer {
|
||||||
// TODO(http://dartbug.com/38721): Change this to an error after
|
// TODO(http://dartbug.com/38721): Change this to an error after
|
||||||
// package:ffi is no longer using sizeOf generically.
|
// package:ffi is no longer using sizeOf generically.
|
||||||
if (!isFfiLibrary) {
|
if (!isFfiLibrary) {
|
||||||
_warningNativeTypeValid(nativeType, node);
|
_ensureNativeTypeValid(nativeType, node);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nativeType is InterfaceType) {
|
if (nativeType is InterfaceType) {
|
||||||
|
@ -467,13 +466,7 @@ class _FfiUseSiteTransformer extends FfiTransformer {
|
||||||
node.receiver.getStaticType(_staticTypeContext);
|
node.receiver.getStaticType(_staticTypeContext);
|
||||||
final DartType nativeType = _pointerTypeGetTypeArg(pointerType);
|
final DartType nativeType = _pointerTypeGetTypeArg(pointerType);
|
||||||
|
|
||||||
_warningNativeTypeValid(nativeType, node);
|
_ensureNativeTypeValid(nativeType, node);
|
||||||
|
|
||||||
// TODO(http://dartbug.com/38721): Change this to an error.
|
|
||||||
if (nativeType is TypeParameterType) {
|
|
||||||
// Do not rewire generic invocations.
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
Expression inlineSizeOf = _inlineSizeOf(nativeType);
|
Expression inlineSizeOf = _inlineSizeOf(nativeType);
|
||||||
if (inlineSizeOf != null) {
|
if (inlineSizeOf != null) {
|
||||||
|
@ -541,22 +534,6 @@ class _FfiUseSiteTransformer extends FfiTransformer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _warningNativeTypeValid(DartType nativeType, Expression node,
|
|
||||||
{bool allowHandle: false, bool allowStructItself = true}) {
|
|
||||||
if (!_nativeTypeValid(nativeType,
|
|
||||||
allowStructs: true,
|
|
||||||
allowStructItself: allowStructItself,
|
|
||||||
allowHandle: allowHandle)) {
|
|
||||||
diagnosticReporter.report(
|
|
||||||
templateFfiNonConstantTypeArgumentWarning.withArguments(
|
|
||||||
nativeType, currentLibrary.isNonNullableByDefault),
|
|
||||||
node.fileOffset,
|
|
||||||
1,
|
|
||||||
node.location.file);
|
|
||||||
throw _FfiStaticTypeError();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void _ensureNoEmptyStructs(DartType nativeType, Expression node) {
|
void _ensureNoEmptyStructs(DartType nativeType, Expression node) {
|
||||||
// Error on structs with no fields.
|
// Error on structs with no fields.
|
||||||
if (nativeType is InterfaceType) {
|
if (nativeType is InterfaceType) {
|
||||||
|
|
|
@ -12,6 +12,7 @@ extension AllocatorAlloc on Allocator {
|
||||||
// TODO(http://dartbug.com/39964): Add `alignmentOf<T>()` call.
|
// TODO(http://dartbug.com/39964): Add `alignmentOf<T>()` call.
|
||||||
@patch
|
@patch
|
||||||
Pointer<T> call<T extends NativeType>([int count = 1]) {
|
Pointer<T> call<T extends NativeType>([int count = 1]) {
|
||||||
return this.allocate(sizeOf<T>() * count);
|
// This case should have been rewritten in pre-processing.
|
||||||
|
throw UnimplementedError("Pointer<$T>");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,19 +26,10 @@ int get _intPtrSize => (const [8, 4, 4])[_abi()];
|
||||||
|
|
||||||
@patch
|
@patch
|
||||||
int sizeOf<T extends NativeType>() {
|
int sizeOf<T extends NativeType>() {
|
||||||
// This is not super fast, but it is faster than a runtime entry.
|
// This case should have been rewritten in pre-processing.
|
||||||
// Hot loops with elementAt().load() do not use this sizeOf, elementAt is
|
throw UnimplementedError("$T");
|
||||||
// optimized per NativeType statically to prevent use of sizeOf at runtime.
|
|
||||||
final int? knownSize = _knownSizes[T];
|
|
||||||
if (knownSize != null) return knownSize;
|
|
||||||
if (T == IntPtr) return _intPtrSize;
|
|
||||||
if (T == Pointer) return _intPtrSize;
|
|
||||||
// For structs we fall back to a runtime entry.
|
|
||||||
return _sizeOf<T>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int _sizeOf<T extends NativeType>() native "Ffi_sizeOf";
|
|
||||||
|
|
||||||
@pragma("vm:recognized", "other")
|
@pragma("vm:recognized", "other")
|
||||||
Pointer<T> _fromAddress<T extends NativeType>(int ptr) native "Ffi_fromAddress";
|
Pointer<T> _fromAddress<T extends NativeType>(int ptr) native "Ffi_fromAddress";
|
||||||
|
|
||||||
|
@ -98,11 +89,13 @@ class Pointer<T extends NativeType> {
|
||||||
@pragma("vm:recognized", "other")
|
@pragma("vm:recognized", "other")
|
||||||
int get address native "Ffi_address";
|
int get address native "Ffi_address";
|
||||||
|
|
||||||
// For statically known types, this is rewired.
|
// For statically known types, this is rewritten.
|
||||||
// (Method sizeOf is slow, see notes above.)
|
|
||||||
@patch
|
@patch
|
||||||
Pointer<T> elementAt(int index) =>
|
Pointer<T> elementAt(int index) {
|
||||||
Pointer.fromAddress(address + sizeOf<T>() * index);
|
// This case should have been rewritten in pre-processing.
|
||||||
|
// Only dynamic invocations are not rewritten in pre-processing.
|
||||||
|
throw UnsupportedError("Pointer.elementAt cannot be called dynamically.");
|
||||||
|
}
|
||||||
|
|
||||||
@patch
|
@patch
|
||||||
Pointer<T> _offsetBy(int offsetInBytes) =>
|
Pointer<T> _offsetBy(int offsetInBytes) =>
|
||||||
|
|
|
@ -24,9 +24,7 @@ part "struct.dart";
|
||||||
///
|
///
|
||||||
/// Includes padding and alignment of structs.
|
/// Includes padding and alignment of structs.
|
||||||
///
|
///
|
||||||
/// Support for invoking this function with non-constant [T] will be removed in
|
/// This function must be invoked with a compile-time constant [T].
|
||||||
/// the next stable version of Dart and it will become mandatory to invoke it
|
|
||||||
/// with a compile-time constant [T].
|
|
||||||
external int sizeOf<T extends NativeType>();
|
external int sizeOf<T extends NativeType>();
|
||||||
|
|
||||||
/// Represents a pointer into the native C memory corresponding to "NULL", e.g.
|
/// Represents a pointer into the native C memory corresponding to "NULL", e.g.
|
||||||
|
@ -65,9 +63,10 @@ class Pointer<T extends NativeType> extends NativeType {
|
||||||
|
|
||||||
/// Pointer arithmetic (takes element size into account).
|
/// Pointer arithmetic (takes element size into account).
|
||||||
///
|
///
|
||||||
/// Support for invoking this method with non-constant [T] will be removed in
|
/// This method must be invoked with a compile-time constant [T].
|
||||||
/// the next stable version of Dart and it will become mandatory to invoke it
|
///
|
||||||
/// with a compile-time constant [T].
|
/// Does not accept dynamic invocations -- where the type of the receiver is
|
||||||
|
/// [dynamic].
|
||||||
external Pointer<T> elementAt(int index);
|
external Pointer<T> elementAt(int index);
|
||||||
|
|
||||||
/// Cast Pointer<T> to a Pointer<V>.
|
/// Cast Pointer<T> to a Pointer<V>.
|
||||||
|
|
|
@ -449,7 +449,7 @@ void testDynamicInvocation() {
|
||||||
final int i = p.value;
|
final int i = p.value;
|
||||||
});
|
});
|
||||||
Expect.throws(() => p.value = 1);
|
Expect.throws(() => p.value = 1);
|
||||||
p.elementAt(5); // Works, but is slow.
|
Expect.throws(() => p.elementAt(5));
|
||||||
final int addr = p.address;
|
final int addr = p.address;
|
||||||
final Pointer<Int16> p2 = p.cast<Int16>();
|
final Pointer<Int16> p2 = p.cast<Int16>();
|
||||||
calloc.free(p);
|
calloc.free(p);
|
||||||
|
|
|
@ -625,7 +625,7 @@ T genericRef3<T extends Struct>(Pointer<T> p) => //# 1202: compile-time error
|
||||||
void testSizeOfGeneric() {
|
void testSizeOfGeneric() {
|
||||||
int generic<T extends Pointer>() {
|
int generic<T extends Pointer>() {
|
||||||
int size = sizeOf<IntPtr>();
|
int size = sizeOf<IntPtr>();
|
||||||
size = sizeOf<T>(); //# 1300: ok
|
size = sizeOf<T>(); //# 1300: compile-time error
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -634,7 +634,7 @@ void testSizeOfGeneric() {
|
||||||
|
|
||||||
void testSizeOfNativeType() {
|
void testSizeOfNativeType() {
|
||||||
try {
|
try {
|
||||||
sizeOf(); //# 1301: ok
|
sizeOf(); //# 1301: compile-time error
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print(e);
|
print(e);
|
||||||
}
|
}
|
||||||
|
@ -643,7 +643,7 @@ void testSizeOfNativeType() {
|
||||||
void testElementAtGeneric() {
|
void testElementAtGeneric() {
|
||||||
Pointer<T> generic<T extends NativeType>(Pointer<T> pointer) {
|
Pointer<T> generic<T extends NativeType>(Pointer<T> pointer) {
|
||||||
Pointer<T> returnValue = pointer;
|
Pointer<T> returnValue = pointer;
|
||||||
returnValue = returnValue.elementAt(1); //# 1310: ok
|
returnValue = returnValue.elementAt(1); //# 1310: compile-time error
|
||||||
return returnValue;
|
return returnValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -657,6 +657,6 @@ void testElementAtNativeType() {
|
||||||
Pointer<Int8> p = calloc();
|
Pointer<Int8> p = calloc();
|
||||||
p.elementAt(1);
|
p.elementAt(1);
|
||||||
Pointer<NativeType> p2 = p;
|
Pointer<NativeType> p2 = p;
|
||||||
p2.elementAt(1); //# 1311: ok
|
p2.elementAt(1); //# 1311: compile-time error
|
||||||
calloc.free(p);
|
calloc.free(p);
|
||||||
}
|
}
|
||||||
|
|
|
@ -449,7 +449,7 @@ void testDynamicInvocation() {
|
||||||
final int i = p.value;
|
final int i = p.value;
|
||||||
});
|
});
|
||||||
Expect.throws(() => p.value = 1);
|
Expect.throws(() => p.value = 1);
|
||||||
p.elementAt(5); // Works, but is slow.
|
Expect.throws(() => p.elementAt(5));
|
||||||
final int addr = p.address;
|
final int addr = p.address;
|
||||||
final Pointer<Int16> p2 = p.cast<Int16>();
|
final Pointer<Int16> p2 = p.cast<Int16>();
|
||||||
calloc.free(p);
|
calloc.free(p);
|
||||||
|
|
|
@ -623,7 +623,7 @@ T genericRef3<T extends Struct>(Pointer<T> p) => //# 1202: compile-time error
|
||||||
void testSizeOfGeneric() {
|
void testSizeOfGeneric() {
|
||||||
int generic<T extends Pointer>() {
|
int generic<T extends Pointer>() {
|
||||||
int size = sizeOf<IntPtr>();
|
int size = sizeOf<IntPtr>();
|
||||||
size = sizeOf<T>(); //# 1300: ok
|
size = sizeOf<T>(); //# 1300: compile-time error
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -632,7 +632,7 @@ void testSizeOfGeneric() {
|
||||||
|
|
||||||
void testSizeOfNativeType() {
|
void testSizeOfNativeType() {
|
||||||
try {
|
try {
|
||||||
sizeOf(); //# 1301: ok
|
sizeOf(); //# 1301: compile-time error
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print(e);
|
print(e);
|
||||||
}
|
}
|
||||||
|
@ -641,7 +641,7 @@ void testSizeOfNativeType() {
|
||||||
void testElementAtGeneric() {
|
void testElementAtGeneric() {
|
||||||
Pointer<T> generic<T extends NativeType>(Pointer<T> pointer) {
|
Pointer<T> generic<T extends NativeType>(Pointer<T> pointer) {
|
||||||
Pointer<T> returnValue = pointer;
|
Pointer<T> returnValue = pointer;
|
||||||
returnValue = returnValue.elementAt(1); //# 1310: ok
|
returnValue = returnValue.elementAt(1); //# 1310: compile-time error
|
||||||
return returnValue;
|
return returnValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -655,6 +655,6 @@ void testElementAtNativeType() {
|
||||||
Pointer<Int8> p = calloc();
|
Pointer<Int8> p = calloc();
|
||||||
p.elementAt(1);
|
p.elementAt(1);
|
||||||
Pointer<NativeType> p2 = p;
|
Pointer<NativeType> p2 = p;
|
||||||
p2.elementAt(1); //# 1311: ok
|
p2.elementAt(1); //# 1311: compile-time error
|
||||||
calloc.free(p);
|
calloc.free(p);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue