Skip to content
Merged
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
6 changes: 6 additions & 0 deletions .bazelci/presubmit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -630,6 +630,12 @@ tasks:
- "--config=no_std_alloc"
test_flags:
- "--config=no_std_alloc"
unstable_rust_features_ubuntu2204:
name: Build with unstable_rust_features
platform: ubuntu2204
working_directory: test/integration/unstable_rust_features
build_targets:
- "//..."
bzlmod_repo_mapping_runfiles:
name: bzlmod repo mapping test
platform: ubuntu2204
Expand Down
5 changes: 5 additions & 0 deletions rust/private/providers.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -229,3 +229,8 @@ AllocatorLibrariesImplInfo = provider(
"static_archive": "Optional[File]: the allocator library archive (typically .a file).",
},
)

UnstableRustFeaturesInfo = provider(
doc = "UnstableRustFeaturesInfo contains a function mapping build targets to unstable features approved for use. Only works on nightly toolchains. May return the special value \"__all__\" to allow all unstable features for the target.",
fields = {"unstable_rust_features_config": "Callable[[Label], List[string]] Returns a list of unstable features approved for use for the given build target."},
)
6 changes: 6 additions & 0 deletions rust/private/rust.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ load(
"CrateGroupInfo",
"CrateInfo",
"LintsInfo",
"UnstableRustFeaturesInfo",
)
load(
":rust_allocator_libraries.bzl",
Expand Down Expand Up @@ -807,6 +808,11 @@ _COMMON_ATTRS = {
"stamp": _stamp_attribute(
default_value = 0,
),
"unstable_rust_features_config": attr.label(
doc = "Controls which unstable features are allowed to be used by this target. Setting this to anything other than None requires a nightly toolchain.",
providers = [UnstableRustFeaturesInfo],
default = None,
Comment thread
FabianWolff marked this conversation as resolved.
),
"version": attr.string(
doc = "A version to inject in the cargo environment variable.",
default = "0.0.0",
Expand Down
48 changes: 42 additions & 6 deletions rust/private/rustc.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ load(
"AlwaysEnableMetadataOutputGroupsInfo",
"LintsInfo",
"RustcOutputDiagnosticsInfo",
"UnstableRustFeaturesInfo",
_BuildInfo = "BuildInfo",
)
load(":rustc_resource_set.bzl", "get_rustc_resource_set", "is_codegen_units_enabled")
Expand Down Expand Up @@ -904,6 +905,15 @@ def _should_add_oso_prefix(toolchain):

return True

def _extract_allowed_unstable_features_from_flags(rust_flags, all_allowed_unstable_features):
other_flags = []
for flag in rust_flags:
if flag.startswith("-Zallow-features="):
all_allowed_unstable_features.extend(flag.removeprefix("-Zallow-features=").split(","))
else:
other_flags.append(flag)
return other_flags

def construct_arguments(
*,
ctx,
Expand Down Expand Up @@ -933,7 +943,8 @@ def construct_arguments(
force_depend_on_objects = False,
skip_expanding_rustc_env = False,
require_explicit_unstable_features = False,
error_format = None):
error_format = None,
allowed_unstable_rust_features = None):
"""Builds an Args object containing common rustc flags

Args:
Expand Down Expand Up @@ -969,6 +980,7 @@ def construct_arguments(
skip_expanding_rustc_env (bool): Whether to skip expanding CrateInfo.rustc_env_attr
require_explicit_unstable_features (bool): Whether to require all unstable features to be explicitly opted in to using `-Zallow-features=...`.
error_format (str, optional): Error format to pass to the `--error-format` command line argument. If set to None, uses the "_error_format" entry in `attr`.
allowed_unstable_rust_features (list, optional): List of unstable Rust language features allowed for this target.

Returns:
tuple: A tuple of the following items
Expand Down Expand Up @@ -996,8 +1008,12 @@ def construct_arguments(

process_wrapper_flags.add_all(build_flags_files, before_each = "--arg-file")

if require_explicit_unstable_features:
process_wrapper_flags.add("--require-explicit-unstable-features", "true")
all_allowed_unstable_features = []
if getattr(ctx.attr, "unstable_rust_features_config", None):
all_allowed_unstable_features.extend(ctx.attr.unstable_rust_features_config[UnstableRustFeaturesInfo].unstable_rust_features_config(ctx.label))

if allowed_unstable_rust_features != None:
all_allowed_unstable_features.extend(allowed_unstable_rust_features)

# Certain rust build processes expect to find files from the environment
# variable `$CARGO_MANIFEST_DIR`. Examples of this include pest, tera,
Expand Down Expand Up @@ -1124,7 +1140,11 @@ def construct_arguments(

# Tell Rustc where to find the standard library (or libcore)
rustc_flags.add_all(toolchain.rust_std_paths, before_each = "-L", format_each = "%s")
rustc_flags.add_all(rust_flags, map_each = map_flag)

rustc_flags.add_all(
_extract_allowed_unstable_features_from_flags(rust_flags, all_allowed_unstable_features),
map_each = map_flag,
)

# Gather data path from crate_info since it is inherited from real crate for rust_doc and rust_test
# Deduplicate data paths due to https://github.com/bazelbuild/bazel/issues/14681
Expand Down Expand Up @@ -1244,7 +1264,18 @@ def construct_arguments(
if hasattr(ctx.attr, "_extra_exec_rustc_env") and is_exec_configuration(ctx):
env.update(ctx.attr._extra_exec_rustc_env[ExtraExecRustcEnvInfo].extra_exec_rustc_env)

rustc_flags.add_all(collect_extra_rustc_flags(ctx, toolchain, crate_info.root, crate_info.type), map_each = map_flag)
extra_rustc_flags = _extract_allowed_unstable_features_from_flags(
collect_extra_rustc_flags(ctx, toolchain, crate_info.root, crate_info.type),
all_allowed_unstable_features,
)
if getattr(ctx.attr, "unstable_rust_features_config", None) and not "__all__" in all_allowed_unstable_features:
all_allowed_unstable_features = {f: None for f in all_allowed_unstable_features}.keys()
extra_rustc_flags.append("-Zallow-features=" + ",".join(all_allowed_unstable_features))

# require_explicit_unstable_features makes no sense when all features are allowed anyway
if require_explicit_unstable_features:
process_wrapper_flags.add("--require-explicit-unstable-features", "true")
rustc_flags.add_all(extra_rustc_flags, map_each = map_flag)

if is_no_std(ctx, toolchain, crate_info.is_test):
rustc_flags.add('--cfg=feature="no_std"')
Expand Down Expand Up @@ -1323,7 +1354,8 @@ def rustc_compile_action(
force_all_deps_direct = False,
crate_info_dict = None,
skip_expanding_rustc_env = False,
include_coverage = True):
include_coverage = True,
allowed_unstable_rust_features = None):
"""Create and run a rustc compile action based on the current rule's attributes

Args:
Expand All @@ -1337,6 +1369,8 @@ def rustc_compile_action(
crate_info_dict: A mutable dict used to create CrateInfo provider
skip_expanding_rustc_env (bool, optional): Whether to expand CrateInfo.rustc_env
include_coverage (bool, optional): Whether to generate coverage information or not.
allowed_unstable_rust_features (list, optional): A list of unstable Rust language features
that are allowed to be used in the crate.

Returns:
list: A list of the following providers:
Expand Down Expand Up @@ -1460,6 +1494,7 @@ def rustc_compile_action(
use_json_output = bool(build_metadata) or bool(rustc_output) or bool(rustc_rmeta_output),
skip_expanding_rustc_env = skip_expanding_rustc_env,
require_explicit_unstable_features = require_explicit_unstable_features,
allowed_unstable_rust_features = allowed_unstable_rust_features,
)

args_metadata = None
Expand Down Expand Up @@ -1487,6 +1522,7 @@ def rustc_compile_action(
use_json_output = True,
build_metadata = True,
require_explicit_unstable_features = require_explicit_unstable_features,
allowed_unstable_rust_features = allowed_unstable_rust_features,
)

env = dict(ctx.configuration.default_shell_env)
Expand Down
2 changes: 2 additions & 0 deletions rust/rust_common.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ load(
_DepInfo = "DepInfo",
_DepVariantInfo = "DepVariantInfo",
_TestCrateInfo = "TestCrateInfo",
_UnstableRustFeaturesInfo = "UnstableRustFeaturesInfo",
)

BuildInfo = _BuildInfo
Expand All @@ -36,5 +37,6 @@ CrateInfo = _CrateInfo
DepInfo = _DepInfo
DepVariantInfo = _DepVariantInfo
TestCrateInfo = _TestCrateInfo
UnstableRustFeaturesInfo = _UnstableRustFeaturesInfo

COMMON_PROVIDERS = _COMMON_PROVIDERS
12 changes: 12 additions & 0 deletions test/integration/unstable_rust_features/.bazelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
###############################################################################
## Incompatibility flags
###############################################################################

# https://github.com/bazelbuild/bazel/issues/8195
Comment thread
FabianWolff marked this conversation as resolved.
build --incompatible_disallow_empty_glob=true

# https://github.com/bazelbuild/bazel/issues/12821
build --nolegacy_external_runfiles

# https://github.com/bazelbuild/bazel/issues/23043.
build --incompatible_autoload_externally=
10 changes: 10 additions & 0 deletions test/integration/unstable_rust_features/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
load("@rules_rust//rust:defs.bzl", "rust_binary")
load(":unstable_features_for_test.bzl", "unstable_rust_features_for_test_rule")

unstable_rust_features_for_test_rule(name = "unstable_rust_features_for_test")

rust_binary(
name = "unstable_features_test",
srcs = ["main.rs"],
unstable_rust_features_config = ":unstable_rust_features_for_test",
)
38 changes: 38 additions & 0 deletions test/integration/unstable_rust_features/MODULE.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
module(
name = "rules_rust_test_unstable_rust_features",
version = "0.0.0",
)

bazel_dep(name = "rules_rust", version = "0.0.0")
local_path_override(
module_name = "rules_rust",
path = "../../..",
)

bazel_dep(name = "rules_cc", version = "0.2.4")
bazel_dep(name = "bazel_skylib", version = "1.8.2")
bazel_dep(name = "platforms", version = "1.0.0")

rust = use_extension("@rules_rust//rust:extensions.bzl", "rust")
rust.toolchain(
edition = "2018",
)

# Use a nightly version where `core_intrinsics` is an unstable feature.
VERSION = "nightly/2026-04-15"

rust.repository_set(
name = "nightly_rust_x86_64",
allocator_library = "@rules_rust//ffi/rs:empty",
edition = "2021",
exec_triple = "x86_64-unknown-linux-gnu",
target_compatible_with = [
"@platforms//cpu:x86_64",
"@platforms//os:linux",
],
target_triple = "x86_64-unknown-linux-gnu",
versions = [VERSION],
)
use_repo(rust, "rust_toolchains")

register_toolchains("@rust_toolchains//:all")
1 change: 1 addition & 0 deletions test/integration/unstable_rust_features/WORKSPACE.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
workspace(name = "rules_rust_test_unstable_rust_features")
7 changes: 7 additions & 0 deletions test/integration/unstable_rust_features/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#![feature(core_intrinsics)]
#![allow(internal_features)]
use std::intrinsics;

fn main() {
intrinsics::abort();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
"""Defines a test rule providing UnstableRustFeaturesInfo"""

load("@rules_rust//rust:rust_common.bzl", "UnstableRustFeaturesInfo")

def _unstable_rust_features_for_test_impl_fn(label):
if str(label).endswith(":unstable_features_test"):
return ["core_intrinsics"]
return []

def _unstable_rust_features_for_test_impl(_ctx):
return UnstableRustFeaturesInfo(
unstable_rust_features_config = _unstable_rust_features_for_test_impl_fn,
)

unstable_rust_features_for_test_rule = rule(
attrs = {},
provides = [UnstableRustFeaturesInfo],
implementation = _unstable_rust_features_for_test_impl,
)
Loading