[dart2wasm] Check import/export pragmas in user code

Change-Id: I926d108a4571d685c67d3a174a8e506910cce8f7
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/369020
Commit-Queue: Ömer Ağacan <omersa@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
This commit is contained in:
Ömer Sinan Ağacan 2024-05-31 09:22:28 +00:00 committed by Commit Queue
parent b56843da32
commit 35bc17a0fa
6 changed files with 87 additions and 1 deletions

View file

@ -17641,6 +17641,17 @@ const MessageCode messageVoidWithTypeArguments = const MessageCode(
correctionMessage: r"""Try removing the type arguments.""",
);
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Code<Null> codeWasmImportOrExportInUserCode =
messageWasmImportOrExportInUserCode;
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const MessageCode messageWasmImportOrExportInUserCode = const MessageCode(
"WasmImportOrExportInUserCode",
problemMessage:
r"""Pragmas `wasm:import` and `wasm:export` are for internal use only and cannot be used by user code.""",
);
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Code<Null> codeWeakReferenceMismatchReturnAndArgumentTypes =
messageWeakReferenceMismatchReturnAndArgumentTypes;

View file

@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:_fe_analyzer_shared/src/messages/codes.dart'
show Message, LocatedMessage;
show Message, LocatedMessage, messageWasmImportOrExportInUserCode;
import 'package:_js_interop_checks/js_interop_checks.dart';
import 'package:_js_interop_checks/src/js_interop.dart' as jsInteropHelper;
import 'package:_js_interop_checks/src/transformations/shared_interop_transformer.dart';
@ -243,6 +243,11 @@ class WasmTarget extends Target {
ReferenceFromIndex? referenceFromIndex,
{void Function(String msg)? logger,
ChangedStructureNotifier? changedStructureNotifier}) {
// Check `wasm:import` and `wasm:export` pragmas before FFI transforms as
// FFI transforms convert JS interop annotations to these pragmas.
_checkWasmImportExportPragmas(libraries, coreTypes,
diagnosticReporter as DiagnosticReporter<Message, LocatedMessage>);
Set<Library> transitiveImportingJSInterop = {
...?jsInteropHelper.calculateTransitiveImportsOfJsInteropIfUsed(
component, Uri.parse("package:js/js.dart")),
@ -518,3 +523,49 @@ class WasmVerification extends Verification {
return false;
}
}
final _dartCoreUri = Uri.parse('dart:core');
/// Check that `wasm:import` and `wasm:export` pragmas are only used in `dart:`
/// libraries and in tests, with the exception of
/// `reject_import_export_pragmas` test.
void _checkWasmImportExportPragmas(List<Library> libraries, CoreTypes coreTypes,
DiagnosticReporter<Message, LocatedMessage> diagnosticReporter) {
for (Library library in libraries) {
final importUri = library.importUri;
if (importUri.isScheme('dart') ||
(importUri.path.contains('tests/web/wasm') &&
!importUri.path.contains('reject_import_export_pragmas'))) {
continue;
}
for (Member member in library.members) {
for (Expression annotation in member.annotations) {
if (annotation is! ConstantExpression) {
continue;
}
final annotationConstant = annotation.constant;
if (annotationConstant is! InstanceConstant) {
continue;
}
final cls = annotationConstant.classNode;
if (cls.name == 'pragma' &&
cls.enclosingLibrary.importUri == _dartCoreUri) {
final pragmaName = annotationConstant
.fieldValues[coreTypes.pragmaName.fieldReference];
if (pragmaName is StringConstant) {
if (pragmaName.value == 'wasm:import' ||
pragmaName.value == 'wasm:export') {
diagnosticReporter.report(
messageWasmImportOrExportInUserCode,
annotation.fileOffset,
0,
library.fileUri,
);
}
}
}
}
}
}
}

View file

@ -1115,6 +1115,8 @@ VarAsTypeName/part_wrapped_script1: Fail
VarAsTypeName/script1: Fail # Too many problems
VariableCouldBeNullDueToWrite/analyzerCode: Fail
VariableCouldBeNullDueToWrite/example: Fail
WasmImportOrExportInUserCode/analyzerCode: Fail
WasmImportOrExportInUserCode/example: Fail
WeakReferenceMismatchReturnAndArgumentTypes/analyzerCode: Fail
WeakReferenceMismatchReturnAndArgumentTypes/example: Fail
WeakReferenceNotOneArgument/analyzerCode: Fail

View file

@ -7011,6 +7011,9 @@ ResourceIdentifiersNotStatic:
ResourceIdentifiersMultiple:
problemMessage: "Only one resource identifier pragma can be used at a time."
WasmImportOrExportInUserCode:
problemMessage: "Pragmas `wasm:import` and `wasm:export` are for internal use only and cannot be used by user code."
WeakReferenceNotStatic:
problemMessage: "Weak reference pragma can be used on a static method only."

View file

@ -114,6 +114,7 @@ placing
pointer`s
pragma
pragma('vm:deeply
pragmas
preexisting
pubspec.yaml
r
@ -149,4 +150,6 @@ u
unavailable
unsound
v
wasm:export
wasm:import
x

View file

@ -0,0 +1,16 @@
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
// Test that importing `dart:ffi` and using `wasm:import` and export pragmas
// are not allowed.
import 'dart:ffi'; //# 01: compile-time error
@pragma('wasm:export', 'f') //# 02: compile-time error
void f() {}
@pragma('wasm:import', 'g') //# 03: compile-time error
external double g(double x);
void main() {}