Auto merge of #111489 - compiler-errors:rollup-g3vgzss, r=compiler-errors
Rollup of 7 pull requests Successful merges: - #106038 (use implied bounds when checking opaque types) - #111366 (Make `NonUseContext::AscribeUserTy` carry `ty::Variance`) - #111375 (CFI: Fix SIGILL reached via trait objects) - #111439 (Fix backtrace normalization in ice-bug-report-url.rs) - #111444 (Only warn single-use lifetime when the binders match.) - #111459 (Update browser-ui-test version to 0.16.0) - #111460 (Improve suggestion for `self: Box<self>`) Failed merges: - #110454 (Require impl Trait in associated types to appear in method signatures) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
699a862a3d
50 changed files with 591 additions and 152 deletions
|
@ -55,7 +55,7 @@ pub fn categorize(context: PlaceContext) -> Option<DefUse> {
|
|||
// `PlaceMention` and `AscribeUserType` both evaluate the place, which must not
|
||||
// contain dangling references.
|
||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::PlaceMention) |
|
||||
PlaceContext::NonUse(NonUseContext::AscribeUserTy) |
|
||||
PlaceContext::NonUse(NonUseContext::AscribeUserTy(_)) |
|
||||
|
||||
PlaceContext::MutatingUse(MutatingUseContext::AddressOf) |
|
||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::AddressOf) |
|
||||
|
|
|
@ -777,7 +777,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
|
|||
Inspect | Copy | Move | PlaceMention | SharedBorrow | ShallowBorrow | UniqueBorrow
|
||||
| AddressOf | Projection,
|
||||
) => ty::Covariant,
|
||||
PlaceContext::NonUse(AscribeUserTy) => ty::Covariant,
|
||||
PlaceContext::NonUse(AscribeUserTy(variance)) => variance,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -94,11 +94,11 @@ pub fn get_fn<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'tcx>) ->
|
|||
// LLVM will prefix the name with `__imp_`. Ideally, we'd like the
|
||||
// existing logic below to set the Storage Class, but it has an
|
||||
// exemption for MinGW for backwards compatability.
|
||||
let llfn = cx.declare_fn(&common::i686_decorated_name(&dllimport, common::is_mingw_gnu_toolchain(&tcx.sess.target), true), fn_abi);
|
||||
let llfn = cx.declare_fn(&common::i686_decorated_name(&dllimport, common::is_mingw_gnu_toolchain(&tcx.sess.target), true), fn_abi, Some(instance));
|
||||
unsafe { llvm::LLVMSetDLLStorageClass(llfn, llvm::DLLStorageClass::DllImport); }
|
||||
llfn
|
||||
} else {
|
||||
cx.declare_fn(sym, fn_abi)
|
||||
cx.declare_fn(sym, fn_abi, Some(instance))
|
||||
};
|
||||
debug!("get_fn: not casting pointer!");
|
||||
|
||||
|
|
|
@ -207,6 +207,7 @@ fn declare_unused_fn<'tcx>(cx: &CodegenCx<'_, 'tcx>, def_id: DefId) -> Instance<
|
|||
)),
|
||||
ty::List::empty(),
|
||||
),
|
||||
None,
|
||||
);
|
||||
|
||||
llvm::set_linkage(llfn, llvm::Linkage::PrivateLinkage);
|
||||
|
|
|
@ -19,8 +19,11 @@ use crate::llvm::AttributePlace::Function;
|
|||
use crate::type_::Type;
|
||||
use crate::value::Value;
|
||||
use rustc_codegen_ssa::traits::TypeMembershipMethods;
|
||||
use rustc_middle::ty::Ty;
|
||||
use rustc_symbol_mangling::typeid::{kcfi_typeid_for_fnabi, typeid_for_fnabi, TypeIdOptions};
|
||||
use rustc_middle::ty::{Instance, Ty};
|
||||
use rustc_symbol_mangling::typeid::{
|
||||
kcfi_typeid_for_fnabi, kcfi_typeid_for_instance, typeid_for_fnabi, typeid_for_instance,
|
||||
TypeIdOptions,
|
||||
};
|
||||
use smallvec::SmallVec;
|
||||
|
||||
/// Declare a function.
|
||||
|
@ -116,7 +119,12 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
|
|||
///
|
||||
/// If there’s a value with the same name already declared, the function will
|
||||
/// update the declaration and return existing Value instead.
|
||||
pub fn declare_fn(&self, name: &str, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> &'ll Value {
|
||||
pub fn declare_fn(
|
||||
&self,
|
||||
name: &str,
|
||||
fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
|
||||
instance: Option<Instance<'tcx>>,
|
||||
) -> &'ll Value {
|
||||
debug!("declare_rust_fn(name={:?}, fn_abi={:?})", name, fn_abi);
|
||||
|
||||
// Function addresses in Rust are never significant, allowing functions to
|
||||
|
@ -132,18 +140,35 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
|
|||
fn_abi.apply_attrs_llfn(self, llfn);
|
||||
|
||||
if self.tcx.sess.is_sanitizer_cfi_enabled() {
|
||||
let typeid = typeid_for_fnabi(self.tcx, fn_abi, TypeIdOptions::empty());
|
||||
self.set_type_metadata(llfn, typeid);
|
||||
let typeid = typeid_for_fnabi(self.tcx, fn_abi, TypeIdOptions::GENERALIZE_POINTERS);
|
||||
self.add_type_metadata(llfn, typeid);
|
||||
let typeid = typeid_for_fnabi(self.tcx, fn_abi, TypeIdOptions::NORMALIZE_INTEGERS);
|
||||
self.add_type_metadata(llfn, typeid);
|
||||
let typeid = typeid_for_fnabi(
|
||||
self.tcx,
|
||||
fn_abi,
|
||||
TypeIdOptions::GENERALIZE_POINTERS | TypeIdOptions::NORMALIZE_INTEGERS,
|
||||
);
|
||||
self.add_type_metadata(llfn, typeid);
|
||||
if let Some(instance) = instance {
|
||||
let typeid = typeid_for_instance(self.tcx, &instance, TypeIdOptions::empty());
|
||||
self.set_type_metadata(llfn, typeid);
|
||||
let typeid =
|
||||
typeid_for_instance(self.tcx, &instance, TypeIdOptions::GENERALIZE_POINTERS);
|
||||
self.add_type_metadata(llfn, typeid);
|
||||
let typeid =
|
||||
typeid_for_instance(self.tcx, &instance, TypeIdOptions::NORMALIZE_INTEGERS);
|
||||
self.add_type_metadata(llfn, typeid);
|
||||
let typeid = typeid_for_instance(
|
||||
self.tcx,
|
||||
&instance,
|
||||
TypeIdOptions::GENERALIZE_POINTERS | TypeIdOptions::NORMALIZE_INTEGERS,
|
||||
);
|
||||
self.add_type_metadata(llfn, typeid);
|
||||
} else {
|
||||
let typeid = typeid_for_fnabi(self.tcx, fn_abi, TypeIdOptions::empty());
|
||||
self.set_type_metadata(llfn, typeid);
|
||||
let typeid = typeid_for_fnabi(self.tcx, fn_abi, TypeIdOptions::GENERALIZE_POINTERS);
|
||||
self.add_type_metadata(llfn, typeid);
|
||||
let typeid = typeid_for_fnabi(self.tcx, fn_abi, TypeIdOptions::NORMALIZE_INTEGERS);
|
||||
self.add_type_metadata(llfn, typeid);
|
||||
let typeid = typeid_for_fnabi(
|
||||
self.tcx,
|
||||
fn_abi,
|
||||
TypeIdOptions::GENERALIZE_POINTERS | TypeIdOptions::NORMALIZE_INTEGERS,
|
||||
);
|
||||
self.add_type_metadata(llfn, typeid);
|
||||
}
|
||||
}
|
||||
|
||||
if self.tcx.sess.is_sanitizer_kcfi_enabled() {
|
||||
|
@ -156,8 +181,13 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
|
|||
options.insert(TypeIdOptions::NORMALIZE_INTEGERS);
|
||||
}
|
||||
|
||||
let kcfi_typeid = kcfi_typeid_for_fnabi(self.tcx, fn_abi, options);
|
||||
self.set_kcfi_type_metadata(llfn, kcfi_typeid);
|
||||
if let Some(instance) = instance {
|
||||
let kcfi_typeid = kcfi_typeid_for_instance(self.tcx, &instance, options);
|
||||
self.set_kcfi_type_metadata(llfn, kcfi_typeid);
|
||||
} else {
|
||||
let kcfi_typeid = kcfi_typeid_for_fnabi(self.tcx, fn_abi, options);
|
||||
self.set_kcfi_type_metadata(llfn, kcfi_typeid);
|
||||
}
|
||||
}
|
||||
|
||||
llfn
|
||||
|
|
|
@ -772,7 +772,7 @@ fn gen_fn<'ll, 'tcx>(
|
|||
) -> (&'ll Type, &'ll Value) {
|
||||
let fn_abi = cx.fn_abi_of_fn_ptr(rust_fn_sig, ty::List::empty());
|
||||
let llty = fn_abi.llvm_type(cx);
|
||||
let llfn = cx.declare_fn(name, fn_abi);
|
||||
let llfn = cx.declare_fn(name, fn_abi, None);
|
||||
cx.set_frame_pointer_type(llfn);
|
||||
cx.apply_target_cpu_attr(llfn);
|
||||
// FIXME(eddyb) find a nicer way to do this.
|
||||
|
|
|
@ -51,7 +51,7 @@ impl<'tcx> PreDefineMethods<'tcx> for CodegenCx<'_, 'tcx> {
|
|||
assert!(!instance.substs.has_infer());
|
||||
|
||||
let fn_abi = self.fn_abi_of_instance(instance, ty::List::empty());
|
||||
let lldecl = self.declare_fn(symbol_name, fn_abi);
|
||||
let lldecl = self.declare_fn(symbol_name, fn_abi, Some(instance));
|
||||
unsafe { llvm::LLVMRustSetLinkage(lldecl, base::linkage_to_llvm(linkage)) };
|
||||
let attrs = self.tcx.codegen_fn_attrs(instance.def_id());
|
||||
base::set_link_section(lldecl, attrs);
|
||||
|
|
|
@ -31,6 +31,7 @@ use rustc_target::abi::FieldIdx;
|
|||
use rustc_target::spec::abi::Abi;
|
||||
use rustc_trait_selection::traits::error_reporting::on_unimplemented::OnUnimplementedDirective;
|
||||
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
|
||||
use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _;
|
||||
use rustc_trait_selection::traits::{self, ObligationCtxt, TraitEngine, TraitEngineExt as _};
|
||||
|
||||
use std::ops::ControlFlow;
|
||||
|
@ -222,7 +223,7 @@ fn check_opaque(tcx: TyCtxt<'_>, id: hir::ItemId) {
|
|||
if check_opaque_for_cycles(tcx, item.owner_id.def_id, substs, span, &origin).is_err() {
|
||||
return;
|
||||
}
|
||||
check_opaque_meets_bounds(tcx, item.owner_id.def_id, substs, span, &origin);
|
||||
check_opaque_meets_bounds(tcx, item.owner_id.def_id, span, &origin);
|
||||
}
|
||||
|
||||
/// Checks that an opaque type does not use `Self` or `T::Foo` projections that would result
|
||||
|
@ -391,7 +392,6 @@ pub(super) fn check_opaque_for_cycles<'tcx>(
|
|||
fn check_opaque_meets_bounds<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
def_id: LocalDefId,
|
||||
substs: SubstsRef<'tcx>,
|
||||
span: Span,
|
||||
origin: &hir::OpaqueTyOrigin,
|
||||
) {
|
||||
|
@ -406,6 +406,8 @@ fn check_opaque_meets_bounds<'tcx>(
|
|||
.with_opaque_type_inference(DefiningAnchor::Bind(defining_use_anchor))
|
||||
.build();
|
||||
let ocx = ObligationCtxt::new(&infcx);
|
||||
|
||||
let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id());
|
||||
let opaque_ty = tcx.mk_opaque(def_id.to_def_id(), substs);
|
||||
|
||||
// `ReErased` regions appear in the "parent_substs" of closures/generators.
|
||||
|
@ -448,9 +450,18 @@ fn check_opaque_meets_bounds<'tcx>(
|
|||
match origin {
|
||||
// Checked when type checking the function containing them.
|
||||
hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..) => {}
|
||||
// Nested opaque types occur only in associated types:
|
||||
// ` type Opaque<T> = impl Trait<&'static T, AssocTy = impl Nested>; `
|
||||
// They can only be referenced as `<Opaque<T> as Trait<&'static T>>::AssocTy`.
|
||||
// We don't have to check them here because their well-formedness follows from the WF of
|
||||
// the projection input types in the defining- and use-sites.
|
||||
hir::OpaqueTyOrigin::TyAlias
|
||||
if tcx.def_kind(tcx.parent(def_id.to_def_id())) == DefKind::OpaqueTy => {}
|
||||
// Can have different predicates to their defining use
|
||||
hir::OpaqueTyOrigin::TyAlias => {
|
||||
let outlives_env = OutlivesEnvironment::new(param_env);
|
||||
let wf_tys = ocx.assumed_wf_types(param_env, span, def_id);
|
||||
let implied_bounds = infcx.implied_bounds_tys(param_env, def_id, wf_tys);
|
||||
let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds);
|
||||
let _ = ocx.resolve_regions_and_report_errors(defining_use_anchor, &outlives_env);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -64,7 +64,7 @@
|
|||
|
||||
use crate::mir::*;
|
||||
use crate::ty::subst::SubstsRef;
|
||||
use crate::ty::{CanonicalUserTypeAnnotation, Ty};
|
||||
use crate::ty::{self, CanonicalUserTypeAnnotation, Ty};
|
||||
use rustc_span::Span;
|
||||
|
||||
macro_rules! make_mir_visitor {
|
||||
|
@ -782,12 +782,12 @@ macro_rules! make_mir_visitor {
|
|||
|
||||
fn super_ascribe_user_ty(&mut self,
|
||||
place: & $($mutability)? Place<'tcx>,
|
||||
_variance: $(& $mutability)? ty::Variance,
|
||||
variance: $(& $mutability)? ty::Variance,
|
||||
user_ty: & $($mutability)? UserTypeProjection,
|
||||
location: Location) {
|
||||
self.visit_place(
|
||||
place,
|
||||
PlaceContext::NonUse(NonUseContext::AscribeUserTy),
|
||||
PlaceContext::NonUse(NonUseContext::AscribeUserTy($(* &$mutability *)? variance)),
|
||||
location
|
||||
);
|
||||
self.visit_user_type_projection(user_ty);
|
||||
|
@ -1320,7 +1320,7 @@ pub enum NonUseContext {
|
|||
/// Ending a storage live range.
|
||||
StorageDead,
|
||||
/// User type annotation assertions for NLL.
|
||||
AscribeUserTy,
|
||||
AscribeUserTy(ty::Variance),
|
||||
/// The data of a user variable, for debug info.
|
||||
VarDebugInfo,
|
||||
}
|
||||
|
|
|
@ -1253,7 +1253,7 @@ pub enum ExplicitSelf<'tcx> {
|
|||
|
||||
impl<'tcx> ExplicitSelf<'tcx> {
|
||||
/// Categorizes an explicit self declaration like `self: SomeType`
|
||||
/// into either `self`, `&self`, `&mut self`, `Box<self>`, or
|
||||
/// into either `self`, `&self`, `&mut self`, `Box<Self>`, or
|
||||
/// `Other`.
|
||||
/// This is mainly used to require the arbitrary_self_types feature
|
||||
/// in the case of `Other`, to improve error messages in the common cases,
|
||||
|
|
|
@ -199,6 +199,10 @@ resolve_invalid_asm_sym =
|
|||
.label = is a local variable
|
||||
.help = `sym` operands must refer to either a function or a static
|
||||
|
||||
resolve_lowercase_self =
|
||||
attempt to use a non-constant value in a constant
|
||||
.suggestion = try using `Self`
|
||||
|
||||
resolve_trait_impl_duplicate =
|
||||
duplicate definitions with name `{$name}`:
|
||||
.label = duplicate definition
|
||||
|
|
|
@ -948,6 +948,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
ResolutionError::InvalidAsmSym => {
|
||||
self.tcx.sess.create_err(errs::InvalidAsmSym { span })
|
||||
}
|
||||
ResolutionError::LowercaseSelf => {
|
||||
self.tcx.sess.create_err(errs::LowercaseSelf { span })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -442,6 +442,14 @@ pub(crate) struct InvalidAsmSym {
|
|||
pub(crate) span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(resolve_lowercase_self)]
|
||||
pub(crate) struct LowercaseSelf {
|
||||
#[primary_span]
|
||||
#[suggestion(code = "Self", applicability = "maybe-incorrect", style = "short")]
|
||||
pub(crate) span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(resolve_trait_impl_duplicate, code = "E0201")]
|
||||
pub(crate) struct TraitImplDuplicate {
|
||||
|
|
|
@ -15,8 +15,7 @@ use std::ptr;
|
|||
|
||||
use crate::errors::{ParamKindInEnumDiscriminant, ParamKindInNonTrivialAnonConst};
|
||||
use crate::late::{
|
||||
ConstantHasGenerics, ConstantItemKind, HasGenericParams, NoConstantGenericsReason, PathSource,
|
||||
Rib, RibKind,
|
||||
ConstantHasGenerics, HasGenericParams, NoConstantGenericsReason, PathSource, Rib, RibKind,
|
||||
};
|
||||
use crate::macros::{sub_namespace_match, MacroRulesScope};
|
||||
use crate::{errors, AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, Determinacy, Finalize};
|
||||
|
@ -1127,28 +1126,25 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
RibKind::ConstantItem(_, item) => {
|
||||
// Still doesn't deal with upvars
|
||||
if let Some(span) = finalize {
|
||||
let (span, resolution_error) =
|
||||
if let Some((ident, constant_item_kind)) = item {
|
||||
let kind_str = match constant_item_kind {
|
||||
ConstantItemKind::Const => "const",
|
||||
ConstantItemKind::Static => "static",
|
||||
};
|
||||
(
|
||||
span,
|
||||
AttemptToUseNonConstantValueInConstant(
|
||||
ident, "let", kind_str,
|
||||
),
|
||||
)
|
||||
} else {
|
||||
(
|
||||
rib_ident.span,
|
||||
AttemptToUseNonConstantValueInConstant(
|
||||
original_rib_ident_def,
|
||||
"const",
|
||||
"let",
|
||||
),
|
||||
)
|
||||
};
|
||||
let (span, resolution_error) = match item {
|
||||
None if rib_ident.as_str() == "self" => (span, LowercaseSelf),
|
||||
None => (
|
||||
rib_ident.span,
|
||||
AttemptToUseNonConstantValueInConstant(
|
||||
original_rib_ident_def,
|
||||
"const",
|
||||
"let",
|
||||
),
|
||||
),
|
||||
Some((ident, kind)) => (
|
||||
span,
|
||||
AttemptToUseNonConstantValueInConstant(
|
||||
ident,
|
||||
"let",
|
||||
kind.as_str(),
|
||||
),
|
||||
),
|
||||
};
|
||||
self.report_error(span, resolution_error);
|
||||
}
|
||||
return Res::Err;
|
||||
|
|
|
@ -150,6 +150,15 @@ pub(crate) enum ConstantItemKind {
|
|||
Static,
|
||||
}
|
||||
|
||||
impl ConstantItemKind {
|
||||
pub(crate) fn as_str(&self) -> &'static str {
|
||||
match self {
|
||||
Self::Const => "const",
|
||||
Self::Static => "static",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
enum RecordPartialRes {
|
||||
Yes,
|
||||
|
@ -1482,7 +1491,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
|
|||
if let Some(&(_, res)) = rib.bindings.get(&normalized_ident) {
|
||||
self.record_lifetime_res(lifetime.id, res, LifetimeElisionCandidate::Named);
|
||||
|
||||
if let LifetimeRes::Param { param, .. } = res {
|
||||
if let LifetimeRes::Param { param, binder } = res {
|
||||
match self.lifetime_uses.entry(param) {
|
||||
Entry::Vacant(v) => {
|
||||
debug!("First use of {:?} at {:?}", res, ident.span);
|
||||
|
@ -1496,10 +1505,16 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
|
|||
LifetimeRibKind::Item
|
||||
| LifetimeRibKind::AnonymousReportError
|
||||
| LifetimeRibKind::ElisionFailure => Some(LifetimeUseSet::Many),
|
||||
// An anonymous lifetime is legal here, go ahead.
|
||||
LifetimeRibKind::AnonymousCreateParameter { .. } => {
|
||||
Some(LifetimeUseSet::One { use_span: ident.span, use_ctxt })
|
||||
}
|
||||
// An anonymous lifetime is legal here, and bound to the right
|
||||
// place, go ahead.
|
||||
LifetimeRibKind::AnonymousCreateParameter {
|
||||
binder: anon_binder,
|
||||
..
|
||||
} => Some(if binder == anon_binder {
|
||||
LifetimeUseSet::One { use_span: ident.span, use_ctxt }
|
||||
} else {
|
||||
LifetimeUseSet::Many
|
||||
}),
|
||||
// Only report if eliding the lifetime would have the same
|
||||
// semantics.
|
||||
LifetimeRibKind::Elided(r) => Some(if res == r {
|
||||
|
|
|
@ -251,6 +251,8 @@ enum ResolutionError<'a> {
|
|||
TraitImplDuplicate { name: Symbol, trait_item_span: Span, old_span: Span },
|
||||
/// Inline asm `sym` operand must refer to a `fn` or `static`.
|
||||
InvalidAsmSym,
|
||||
/// `self` used instead of `Self` in a generic parameter
|
||||
LowercaseSelf,
|
||||
}
|
||||
|
||||
enum VisResolutionError<'a> {
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
/// For more information about LLVM CFI and cross-language LLVM CFI support for the Rust compiler,
|
||||
/// see design document in the tracking issue #89653.
|
||||
use bitflags::bitflags;
|
||||
use rustc_middle::ty::{FnSig, Ty, TyCtxt};
|
||||
use rustc_middle::ty::{FnSig, Instance, Ty, TyCtxt};
|
||||
use rustc_target::abi::call::FnAbi;
|
||||
use std::hash::Hasher;
|
||||
use twox_hash::XxHash64;
|
||||
|
@ -38,6 +38,15 @@ pub fn typeid_for_fnsig<'tcx>(
|
|||
typeid_itanium_cxx_abi::typeid_for_fnsig(tcx, fn_sig, options)
|
||||
}
|
||||
|
||||
/// Returns a type metadata identifier for the specified Instance.
|
||||
pub fn typeid_for_instance<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
instance: &Instance<'tcx>,
|
||||
options: TypeIdOptions,
|
||||
) -> String {
|
||||
typeid_itanium_cxx_abi::typeid_for_instance(tcx, instance, options)
|
||||
}
|
||||
|
||||
/// Returns a KCFI type metadata identifier for the specified FnAbi.
|
||||
pub fn kcfi_typeid_for_fnabi<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
|
@ -63,3 +72,16 @@ pub fn kcfi_typeid_for_fnsig<'tcx>(
|
|||
hash.write(typeid_itanium_cxx_abi::typeid_for_fnsig(tcx, fn_sig, options).as_bytes());
|
||||
hash.finish() as u32
|
||||
}
|
||||
|
||||
/// Returns a KCFI type metadata identifier for the specified Instance.
|
||||
pub fn kcfi_typeid_for_instance<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
instance: &Instance<'tcx>,
|
||||
options: TypeIdOptions,
|
||||
) -> u32 {
|
||||
// A KCFI type metadata identifier is a 32-bit constant produced by taking the lower half of the
|
||||
// xxHash64 of the type metadata identifier. (See llvm/llvm-project@cff5bef.)
|
||||
let mut hash: XxHash64 = Default::default();
|
||||
hash.write(typeid_itanium_cxx_abi::typeid_for_instance(tcx, instance, options).as_bytes());
|
||||
hash.finish() as u32
|
||||
}
|
||||
|
|
|
@ -14,8 +14,8 @@ use rustc_errors::DiagnosticMessage;
|
|||
use rustc_hir as hir;
|
||||
use rustc_middle::ty::subst::{GenericArg, GenericArgKind, SubstsRef};
|
||||
use rustc_middle::ty::{
|
||||
self, Const, ExistentialPredicate, FloatTy, FnSig, IntTy, List, Region, RegionKind, TermKind,
|
||||
Ty, TyCtxt, UintTy,
|
||||
self, Const, ExistentialPredicate, FloatTy, FnSig, Instance, IntTy, List, Region, RegionKind,
|
||||
TermKind, Ty, TyCtxt, UintTy,
|
||||
};
|
||||
use rustc_span::def_id::DefId;
|
||||
use rustc_span::sym;
|
||||
|
@ -1010,3 +1010,56 @@ pub fn typeid_for_fnsig<'tcx>(
|
|||
|
||||
typeid
|
||||
}
|
||||
|
||||
/// Returns a type metadata identifier for the specified Instance using the Itanium C++ ABI with
|
||||
/// vendor extended type qualifiers and types for Rust types that are not used at the FFI boundary.
|
||||
pub fn typeid_for_instance<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
instance: &Instance<'tcx>,
|
||||
options: TypeIdOptions,
|
||||
) -> String {
|
||||
let fn_abi = tcx
|
||||
.fn_abi_of_instance(tcx.param_env(instance.def_id()).and((*instance, ty::List::empty())))
|
||||
.unwrap_or_else(|instance| {
|
||||
bug!("typeid_for_instance: couldn't get fn_abi of instance {:?}", instance)
|
||||
});
|
||||
|
||||
// If this instance is a method and self is a reference, get the impl it belongs to
|
||||
let impl_def_id = tcx.impl_of_method(instance.def_id());
|
||||
if impl_def_id.is_some() && !fn_abi.args.is_empty() && fn_abi.args[0].layout.ty.is_ref() {
|
||||
// If this impl is not an inherent impl, get the trait it implements
|
||||
if let Some(trait_ref) = tcx.impl_trait_ref(impl_def_id.unwrap()) {
|
||||
// Transform the concrete self into a reference to a trait object
|
||||
let existential_predicate = trait_ref.map_bound(|trait_ref| {
|
||||
ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef::erase_self_ty(
|
||||
tcx, trait_ref,
|
||||
))
|
||||
});
|
||||
let existential_predicates = tcx.mk_poly_existential_predicates(&[ty::Binder::dummy(
|
||||
existential_predicate.skip_binder(),
|
||||
)]);
|
||||
// Is the concrete self mutable?
|
||||
let self_ty = if fn_abi.args[0].layout.ty.is_mutable_ptr() {
|
||||
tcx.mk_mut_ref(
|
||||
tcx.lifetimes.re_erased,
|
||||
tcx.mk_dynamic(existential_predicates, tcx.lifetimes.re_erased, ty::Dyn),
|
||||
)
|
||||
} else {
|
||||
tcx.mk_imm_ref(
|
||||
tcx.lifetimes.re_erased,
|
||||
tcx.mk_dynamic(existential_predicates, tcx.lifetimes.re_erased, ty::Dyn),
|
||||
)
|
||||
};
|
||||
|
||||
// Replace the concrete self in an fn_abi clone by the reference to a trait object
|
||||
let mut fn_abi = fn_abi.clone();
|
||||
// HACK(rcvalle): It is okay to not replace or update the entire ArgAbi here because the
|
||||
// other fields are never used.
|
||||
fn_abi.args[0].layout.ty = self_ty;
|
||||
|
||||
return typeid_for_fnabi(tcx, &fn_abi, options);
|
||||
}
|
||||
}
|
||||
|
||||
typeid_for_fnabi(tcx, &fn_abi, options)
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ mod x86;
|
|||
mod x86_64;
|
||||
mod x86_win64;
|
||||
|
||||
#[derive(PartialEq, Eq, Hash, Debug, HashStable_Generic)]
|
||||
#[derive(Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
|
||||
pub enum PassMode {
|
||||
/// Ignore the argument.
|
||||
///
|
||||
|
@ -211,7 +211,7 @@ impl Uniform {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
|
||||
#[derive(Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
|
||||
pub struct CastTarget {
|
||||
pub prefix: [Option<Reg>; 8],
|
||||
pub rest: Uniform,
|
||||
|
@ -458,7 +458,7 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
|
|||
|
||||
/// Information about how to pass an argument to,
|
||||
/// or return a value from, a function, under some ABI.
|
||||
#[derive(PartialEq, Eq, Hash, Debug, HashStable_Generic)]
|
||||
#[derive(Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
|
||||
pub struct ArgAbi<'a, Ty> {
|
||||
pub layout: TyAndLayout<'a, Ty>,
|
||||
pub mode: PassMode,
|
||||
|
@ -605,7 +605,7 @@ pub enum Conv {
|
|||
///
|
||||
/// I will do my best to describe this structure, but these
|
||||
/// comments are reverse-engineered and may be inaccurate. -NDM
|
||||
#[derive(PartialEq, Eq, Hash, Debug, HashStable_Generic)]
|
||||
#[derive(Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
|
||||
pub struct FnAbi<'a, Ty> {
|
||||
/// The LLVM types of each argument.
|
||||
pub args: Box<[ArgAbi<'a, Ty>]>,
|
||||
|
|
|
@ -31,6 +31,18 @@ fn assumed_wf_types(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::List<Ty<'_>> {
|
|||
}
|
||||
}
|
||||
DefKind::AssocConst | DefKind::AssocTy => tcx.assumed_wf_types(tcx.parent(def_id)),
|
||||
DefKind::OpaqueTy => match tcx.def_kind(tcx.parent(def_id)) {
|
||||
DefKind::TyAlias => ty::List::empty(),
|
||||
DefKind::AssocTy => tcx.assumed_wf_types(tcx.parent(def_id)),
|
||||
// Nested opaque types only occur in associated types:
|
||||
// ` type Opaque<T> = impl Trait<&'static T, AssocTy = impl Nested>; `
|
||||
// assumed_wf_types should include those of `Opaque<T>`, `Opaque<T>` itself
|
||||
// and `&'static T`.
|
||||
DefKind::OpaqueTy => bug!("unimplemented implied bounds for neseted opaque types"),
|
||||
def_kind @ _ => {
|
||||
bug!("unimplemented implied bounds for opaque types with parent {def_kind:?}")
|
||||
}
|
||||
},
|
||||
DefKind::Mod
|
||||
| DefKind::Struct
|
||||
| DefKind::Union
|
||||
|
@ -51,7 +63,6 @@ fn assumed_wf_types(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::List<Ty<'_>> {
|
|||
| DefKind::ForeignMod
|
||||
| DefKind::AnonConst
|
||||
| DefKind::InlineConst
|
||||
| DefKind::OpaqueTy
|
||||
| DefKind::ImplTraitPlaceholder
|
||||
| DefKind::Field
|
||||
| DefKind::LifetimeParam
|
||||
|
|
|
@ -643,7 +643,7 @@ impl UnifyKey for FloatVid {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Decodable, Encodable, Hash, HashStable_Generic)]
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Decodable, Encodable, Hash, HashStable_Generic)]
|
||||
#[rustc_pass_by_value]
|
||||
pub enum Variance {
|
||||
Covariant, // T<A> <: T<B> iff A <: B -- e.g., function return type
|
||||
|
|
|
@ -1 +1 @@
|
|||
0.15.0
|
||||
0.16.0
|
|
@ -143,7 +143,7 @@ async function runTests(opts, framework_options, files, results, status_bar, sho
|
|||
const tests_queue = [];
|
||||
|
||||
for (const testPath of files) {
|
||||
const callback = runTest(testPath, framework_options)
|
||||
const callback = runTest(testPath, {"options": framework_options})
|
||||
.then(out => {
|
||||
const [output, nb_failures] = out;
|
||||
results[nb_failures === 0 ? "successful" : "failed"].push({
|
||||
|
@ -323,6 +323,7 @@ async function main(argv) {
|
|||
if (results.failed.length > 0 || results.errored.length > 0) {
|
||||
process.exit(1);
|
||||
}
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
main(process.argv);
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
// Verifies that type metadata identifiers for trait objects are emitted correctly.
|
||||
//
|
||||
// needs-sanitizer-cfi
|
||||
// compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi
|
||||
|
||||
#![crate_type="lib"]
|
||||
|
||||
trait Trait1 {
|
||||
fn foo(&self);
|
||||
}
|
||||
|
||||
struct Type1;
|
||||
|
||||
impl Trait1 for Type1 {
|
||||
fn foo(&self) {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn foo() {
|
||||
let a = Type1;
|
||||
a.foo();
|
||||
// CHECK-LABEL: define{{.*}}foo{{.*}}!type !{{[0-9]+}}
|
||||
// CHECK: call <sanitizer_cfi_emit_type_metadata_trait_objects::Type1 as sanitizer_cfi_emit_type_metadata_trait_objects::Trait1>::foo
|
||||
}
|
||||
|
||||
pub fn bar() {
|
||||
let a = Type1;
|
||||
let b = &a as &dyn Trait1;
|
||||
b.foo();
|
||||
// CHECK-LABEL: define{{.*}}bar{{.*}}!type !{{[0-9]+}}
|
||||
// CHECK: call i1 @llvm.type.test({{i8\*|ptr}} {{%f|%0|%1}}, metadata !"[[TYPE1:[[:print:]]+]]")
|
||||
}
|
||||
|
||||
pub fn baz() {
|
||||
let a = Type1;
|
||||
let b = &a as &dyn Trait1;
|
||||
a.foo();
|
||||
b.foo();
|
||||
// CHECK-LABEL: define{{.*}}baz{{.*}}!type !{{[0-9]+}}
|
||||
// CHECK: call <sanitizer_cfi_emit_type_metadata_trait_objects::Type1 as sanitizer_cfi_emit_type_metadata_trait_objects::Trait1>::foo
|
||||
// CHECK: call i1 @llvm.type.test({{i8\*|ptr}} {{%f|%0|%1}}, metadata !"[[TYPE1:[[:print:]]+]]")
|
||||
}
|
||||
|
||||
// CHECK: !{{[0-9]+}} = !{i64 0, !"[[TYPE1]]"}
|
|
@ -0,0 +1,69 @@
|
|||
// Verifies that type metadata identifiers for trait objects are emitted correctly.
|
||||
//
|
||||
// revisions: aarch64 x86_64
|
||||
// [aarch64] compile-flags: --target aarch64-unknown-none
|
||||
// [aarch64] needs-llvm-components: aarch64
|
||||
// [x86_64] compile-flags: --target x86_64-unknown-none
|
||||
// [x86_64] needs-llvm-components:
|
||||
// compile-flags: -Cno-prepopulate-passes -Zsanitizer=kcfi -Copt-level=0
|
||||
|
||||
#![crate_type="lib"]
|
||||
#![feature(arbitrary_self_types, no_core, lang_items)]
|
||||
#![no_core]
|
||||
|
||||
#[lang="sized"]
|
||||
trait Sized { }
|
||||
#[lang="copy"]
|
||||
trait Copy { }
|
||||
#[lang="receiver"]
|
||||
trait Receiver { }
|
||||
#[lang="dispatch_from_dyn"]
|
||||
trait DispatchFromDyn<T> { }
|
||||
impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<&'a U> for &'a T {}
|
||||
#[lang = "unsize"]
|
||||
trait Unsize<T: ?Sized> { }
|
||||
#[lang = "coerce_unsized"]
|
||||
pub trait CoerceUnsized<T: ?Sized> { }
|
||||
impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {}
|
||||
#[lang="freeze"]
|
||||
trait Freeze { }
|
||||
#[lang="drop_in_place"]
|
||||
fn drop_in_place_fn<T>() { }
|
||||
|
||||
trait Trait1 {
|
||||
fn foo(&self);
|
||||
}
|
||||
|
||||
struct Type1;
|
||||
|
||||
impl Trait1 for Type1 {
|
||||
fn foo(&self) {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn foo() {
|
||||
let a = Type1;
|
||||
a.foo();
|
||||
// CHECK-LABEL: define{{.*}}foo{{.*}}!{{<unknown kind #36>|kcfi_type}} !{{[0-9]+}}
|
||||
// CHECK: call <sanitizer_kcfi_emit_type_metadata_trait_objects::Type1 as sanitizer_kcfi_emit_type_metadata_trait_objects::Trait1>::foo
|
||||
}
|
||||
|
||||
pub fn bar() {
|
||||
let a = Type1;
|
||||
let b = &a as &dyn Trait1;
|
||||
b.foo();
|
||||
// CHECK-LABEL: define{{.*}}bar{{.*}}!{{<unknown kind #36>|kcfi_type}} !{{[0-9]+}}
|
||||
// CHECK: call void %0({{\{\}\*|ptr}} align 1 {{%b\.0|%_1}}){{.*}}[ "kcfi"(i32 [[TYPE1:[[:print:]]+]]) ]
|
||||
}
|
||||
|
||||
pub fn baz() {
|
||||
let a = Type1;
|
||||
let b = &a as &dyn Trait1;
|
||||
a.foo();
|
||||
b.foo();
|
||||
// CHECK-LABEL: define{{.*}}baz{{.*}}!{{<unknown kind #36>|kcfi_type}} !{{[0-9]+}}
|
||||
// CHECK: call <sanitizer_kcfi_emit_type_metadata_trait_objects::Type1 as sanitizer_kcfi_emit_type_metadata_trait_objects::Trait1>::foo
|
||||
// CHECK: call void %0({{\{\}\*|ptr}} align 1 {{%b\.0|%_1}}){{.*}}[ "kcfi"(i32 [[TYPE1:[[:print:]]+]]) ]
|
||||
}
|
||||
|
||||
// CHECK: !{{[0-9]+}} = !{i32 [[TYPE1]]}
|
|
@ -7,20 +7,26 @@ set-window-size: (786, 600)
|
|||
// Confirms that there 3 paragraphs.
|
||||
assert-count: (".top-doc .docblock p", 3)
|
||||
// Checking that there is no scrollable content.
|
||||
store-property: (clientHeight, ".top-doc .docblock p:nth-of-type(1)", "clientHeight")
|
||||
store-property: (clientWidth, ".top-doc .docblock p:nth-of-type(1)", "clientWidth")
|
||||
store-property: (".top-doc .docblock p:nth-of-type(1)", {
|
||||
"clientHeight": clientHeight,
|
||||
"clientWidth": clientWidth,
|
||||
})
|
||||
assert-property: (
|
||||
".top-doc .docblock p:nth-of-type(1)",
|
||||
{"scrollHeight": |clientHeight|, "scrollWidth": |clientWidth|},
|
||||
)
|
||||
store-property: (clientHeight, ".top-doc .docblock p:nth-of-type(2)", "clientHeight")
|
||||
store-property: (clientWidth, ".top-doc .docblock p:nth-of-type(2)", "clientWidth")
|
||||
store-property: (".top-doc .docblock p:nth-of-type(2)", {
|
||||
"clientHeight": clientHeight,
|
||||
"clientWidth": clientWidth,
|
||||
})
|
||||
assert-property: (
|
||||
".top-doc .docblock p:nth-of-type(2)",
|
||||
{"scrollHeight": |clientHeight|, "scrollWidth": |clientWidth|},
|
||||
)
|
||||
store-property: (clientHeight, ".top-doc .docblock p:nth-of-type(3)", "clientHeight")
|
||||
store-property: (clientWidth, ".top-doc .docblock p:nth-of-type(3)", "clientWidth")
|
||||
store-property: (".top-doc .docblock p:nth-of-type(3)", {
|
||||
"clientHeight": clientHeight,
|
||||
"clientWidth": clientWidth,
|
||||
})
|
||||
assert-property: (
|
||||
".top-doc .docblock p:nth-of-type(3)",
|
||||
{"scrollHeight": |clientHeight|, "scrollWidth": |clientWidth|},
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Test that code blocks nested within <sub> do not have a line height of 0.
|
||||
go-to: "file://" + |DOC_PATH| + "/test_docs/codeblock_sub/index.html"
|
||||
|
||||
store-property: (codeblock_sub_1, "#codeblock-sub-1", "offsetHeight")
|
||||
store-property: ("#codeblock-sub-1", {"offsetHeight": codeblock_sub_1})
|
||||
assert-property-false: ("#codeblock-sub-3", { "offsetHeight": |codeblock_sub_1| })
|
||||
|
|
|
@ -9,7 +9,7 @@ reload:
|
|||
assert-text: (".top-doc .docblock > h3", "Hello")
|
||||
assert-css: (
|
||||
".top-doc .docblock > h3",
|
||||
{"border-bottom": "1px solid rgb(210, 210, 210)"},
|
||||
{"border-bottom": "1px solid #d2d2d2"},
|
||||
)
|
||||
// We now check that the `<summary>` doesn't have a bottom border and has the correct display.
|
||||
assert-css: (
|
||||
|
|
|
@ -4,8 +4,8 @@ go-to: "file://" + |DOC_PATH| + "/lib2/struct.Foo.html"
|
|||
// We set a fixed size so there is no chance of "random" resize.
|
||||
set-window-size: (1100, 800)
|
||||
// We check that ".item-info" is bigger than its content.
|
||||
assert-css: (".item-info", {"width": "840px"})
|
||||
assert-css: (".item-info .stab", {"width": "289px"})
|
||||
assert-size: (".item-info", {"width": 840})
|
||||
assert-size: (".item-info .stab", {"width": 289})
|
||||
assert-position: (".item-info .stab", {"x": 245})
|
||||
|
||||
// Now we ensure that they're not rendered on the same line.
|
||||
|
|
|
@ -225,12 +225,12 @@ assert: "#method\.create_an_iterator_from_read .tooltip:focus"
|
|||
|
||||
// Now we check that the focus isn't given back to the wrong item when opening
|
||||
// another popover.
|
||||
store-window-property: (scroll, "scrollY")
|
||||
store-window-property: {"scrollY": scroll}
|
||||
click: "#method\.create_an_iterator_from_read .fn"
|
||||
// We ensure that the scroll position changed.
|
||||
assert-window-property-false: {"scrollY": |scroll|}
|
||||
// Store the new position.
|
||||
store-window-property: (scroll, "scrollY")
|
||||
store-window-property: {"scrollY": scroll}
|
||||
click: "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']"
|
||||
wait-for: "//*[@class='tooltip popover']"
|
||||
click: "#settings-menu a"
|
||||
|
@ -239,12 +239,12 @@ click: ".search-input"
|
|||
assert-window-property-false: {"scrollY": |scroll|}
|
||||
|
||||
// Same but with Escape handling.
|
||||
store-window-property: (scroll, "scrollY")
|
||||
store-window-property: {"scrollY": scroll}
|
||||
click: "#method\.create_an_iterator_from_read .fn"
|
||||
// We ensure that the scroll position changed.
|
||||
assert-window-property-false: {"scrollY": |scroll|}
|
||||
// Store the new position.
|
||||
store-window-property: (scroll, "scrollY")
|
||||
store-window-property: {"scrollY": scroll}
|
||||
click: "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']"
|
||||
wait-for: "//*[@class='tooltip popover']"
|
||||
click: "#settings-menu a"
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
go-to: "file://" + |DOC_PATH| + "/scrape_examples/fn.test.html"
|
||||
|
||||
// The next/prev buttons vertically scroll the code viewport between examples
|
||||
store-property: (initialScrollTop, ".scraped-example-list > .scraped-example pre", "scrollTop")
|
||||
store-property: (".scraped-example-list > .scraped-example pre", {"scrollTop": initialScrollTop})
|
||||
focus: ".scraped-example-list > .scraped-example .next"
|
||||
press-key: "Enter"
|
||||
assert-property-false: (".scraped-example-list > .scraped-example pre", {
|
||||
|
@ -16,7 +16,7 @@ assert-property: (".scraped-example-list > .scraped-example pre", {
|
|||
}, NEAR)
|
||||
|
||||
// The expand button increases the scrollHeight of the minimized code viewport
|
||||
store-property: (smallOffsetHeight, ".scraped-example-list > .scraped-example pre", "offsetHeight")
|
||||
store-property: (".scraped-example-list > .scraped-example pre", {"offsetHeight": smallOffsetHeight})
|
||||
assert-property-false: (".scraped-example-list > .scraped-example pre", {
|
||||
"scrollHeight": |smallOffsetHeight|
|
||||
}, NEAR)
|
||||
|
@ -25,7 +25,7 @@ press-key: "Enter"
|
|||
assert-property-false: (".scraped-example-list > .scraped-example pre", {
|
||||
"offsetHeight": |smallOffsetHeight|
|
||||
}, NEAR)
|
||||
store-property: (fullOffsetHeight, ".scraped-example-list > .scraped-example pre", "offsetHeight")
|
||||
store-property: (".scraped-example-list > .scraped-example pre", {"offsetHeight": fullOffsetHeight})
|
||||
assert-property: (".scraped-example-list > .scraped-example pre", {
|
||||
"scrollHeight": |fullOffsetHeight|
|
||||
}, NEAR)
|
||||
|
|
|
@ -9,9 +9,8 @@ assert-property-false: (
|
|||
|
||||
// Check that examples with very long lines have the same width as ones that don't.
|
||||
store-property: (
|
||||
clientWidth,
|
||||
".more-scraped-examples .scraped-example:nth-child(2) .code-wrapper .src-line-numbers",
|
||||
"clientWidth"
|
||||
{"clientWidth": clientWidth},
|
||||
)
|
||||
|
||||
assert-property: (
|
||||
|
@ -40,8 +39,8 @@ assert-property: (
|
|||
store-value: (offset_y, 4)
|
||||
|
||||
// First with desktop
|
||||
assert-position: (".scraped-example .code-wrapper", {"y": 253})
|
||||
assert-position: (".scraped-example .code-wrapper .prev", {"y": 253 + |offset_y|})
|
||||
assert-position: (".scraped-example .code-wrapper", {"y": 226})
|
||||
assert-position: (".scraped-example .code-wrapper .prev", {"y": 226 + |offset_y|})
|
||||
|
||||
// Then with mobile
|
||||
set-window-size: (600, 600)
|
||||
|
|
|
@ -32,8 +32,8 @@ set-text: (
|
|||
)
|
||||
|
||||
// Then we compare again to confirm the height didn't change.
|
||||
assert-css: ("#crate-search", {"width": "527px"})
|
||||
assert-css: (".search-results-title", {"height": "50px", "width": "640px"})
|
||||
assert-size: ("#crate-search", {"width": 527})
|
||||
assert-size: (".search-results-title", {"height": 50, "width": 640})
|
||||
// And we check that the `<select>` isn't bigger than its container (".search-results-title").
|
||||
assert-css: ("#search", {"width": "640px"})
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ wait-for: "#settings"
|
|||
assert-css: ("#settings", {"display": "block"})
|
||||
|
||||
// Store the line margin to compare with the settings.html later.
|
||||
store-css: (setting_line_margin, ".setting-line", "margin")
|
||||
store-css: (".setting-line", {"margin": setting_line_margin})
|
||||
|
||||
// Let's close it by clicking on the same button.
|
||||
click: "#settings-menu"
|
||||
|
|
|
@ -121,28 +121,28 @@ define-function: (
|
|||
|
||||
call-function: ("check-colors", {
|
||||
"theme": "light",
|
||||
"color": "rgb(0, 0, 0)",
|
||||
"color_hover": "rgb(0, 0, 0)",
|
||||
"background": "rgb(255, 255, 255)",
|
||||
"background_hover": "rgb(224, 224, 224)",
|
||||
"color": "black",
|
||||
"color_hover": "#000",
|
||||
"background": "#fff",
|
||||
"background_hover": "#e0e0e0",
|
||||
"background_toggle": "rgba(0, 0, 0, 0)",
|
||||
"background_toggle_hover": "rgb(224, 224, 224)",
|
||||
"background_toggle_hover": "#e0e0e0",
|
||||
})
|
||||
call-function: ("check-colors", {
|
||||
"theme": "dark",
|
||||
"color": "rgb(221, 221, 221)",
|
||||
"color_hover": "rgb(221, 221, 221)",
|
||||
"background": "rgb(51, 51, 51)",
|
||||
"background_hover": "rgb(68, 68, 68)",
|
||||
"color": "#ddd",
|
||||
"color_hover": "#ddd",
|
||||
"background": "#333",
|
||||
"background_hover": "#444",
|
||||
"background_toggle": "rgba(0, 0, 0, 0)",
|
||||
"background_toggle_hover": "rgb(103, 103, 103)",
|
||||
"background_toggle_hover": "#676767",
|
||||
})
|
||||
call-function: ("check-colors", {
|
||||
"theme": "ayu",
|
||||
"color": "rgb(197, 197, 197)",
|
||||
"color_hover": "rgb(255, 180, 76)",
|
||||
"color": "#c5c5c5",
|
||||
"color_hover": "#ffb44c",
|
||||
"background": "rgb(20, 25, 31)",
|
||||
"background_hover": "rgb(20, 25, 31)",
|
||||
"background_hover": "#14191f",
|
||||
"background_toggle": "rgba(0, 0, 0, 0)",
|
||||
"background_toggle_hover": "rgba(70, 70, 70, 0.33)",
|
||||
})
|
||||
|
|
|
@ -152,14 +152,16 @@ assert-property: (".sidebar", {"clientWidth": "200"})
|
|||
|
||||
// Checks that all.html and index.html have their sidebar link in the same place.
|
||||
go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
|
||||
store-property: (index_sidebar_width, ".sidebar .location a", "clientWidth")
|
||||
store-property: (index_sidebar_height, ".sidebar .location a", "clientHeight")
|
||||
store-property: (index_sidebar_x, ".sidebar .location a", "offsetTop")
|
||||
store-property: (index_sidebar_y, ".sidebar .location a", "offsetLeft")
|
||||
store-property: (".sidebar .location a", {
|
||||
"clientWidth": index_sidebar_width,
|
||||
"clientHeight": index_sidebar_height,
|
||||
"offsetTop": index_sidebar_y,
|
||||
"offsetLeft": index_sidebar_x,
|
||||
})
|
||||
go-to: "file://" + |DOC_PATH| + "/test_docs/all.html"
|
||||
assert-property: (".sidebar .location a", {
|
||||
"clientWidth": |index_sidebar_width|,
|
||||
"clientHeight": |index_sidebar_height|,
|
||||
"offsetTop": |index_sidebar_x|,
|
||||
"offsetLeft": |index_sidebar_y|,
|
||||
"offsetTop": |index_sidebar_y|,
|
||||
"offsetLeft": |index_sidebar_x|,
|
||||
})
|
||||
|
|
|
@ -117,9 +117,8 @@ assert-property: ("#source-sidebar details:first-of-type", {"open": "true"})
|
|||
|
||||
// Check the sidebar directory entries have a marker and spacing (desktop).
|
||||
store-property: (
|
||||
link_height,
|
||||
"#source-sidebar > details:first-of-type.dir-entry[open] > .files > a",
|
||||
"offsetHeight"
|
||||
{"offsetHeight": link_height},
|
||||
)
|
||||
define-function: (
|
||||
"check-sidebar-dir-entry",
|
||||
|
@ -147,16 +146,10 @@ define-function: (
|
|||
)
|
||||
}
|
||||
)
|
||||
store-property: (
|
||||
source_sidebar_title_height,
|
||||
"#source-sidebar > .title",
|
||||
"offsetHeight"
|
||||
)
|
||||
store-property: (
|
||||
source_sidebar_title_y,
|
||||
"#source-sidebar > .title",
|
||||
"offsetTop"
|
||||
)
|
||||
store-property: ("#source-sidebar > .title", {
|
||||
"offsetHeight": source_sidebar_title_height,
|
||||
"offsetTop": source_sidebar_title_y,
|
||||
})
|
||||
call-function: ("check-sidebar-dir-entry", {
|
||||
"x": 0,
|
||||
// border + margin = 6
|
||||
|
@ -182,16 +175,10 @@ assert-property: ("#main-content", {"offsetTop": 76})
|
|||
// 21 = 76 - 34 - 21
|
||||
|
||||
// Check the sidebar directory entries have a marker and spacing (tablet).
|
||||
store-property: (
|
||||
source_sidebar_title_height,
|
||||
"#source-sidebar > .title",
|
||||
"offsetHeight"
|
||||
)
|
||||
store-property: (
|
||||
source_sidebar_title_y,
|
||||
"#source-sidebar > .title",
|
||||
"offsetTop"
|
||||
)
|
||||
store-property: ("#source-sidebar > .title", {
|
||||
"offsetHeight": source_sidebar_title_height,
|
||||
"offsetTop": source_sidebar_title_y,
|
||||
})
|
||||
call-function: ("check-sidebar-dir-entry", {
|
||||
"x": 0,
|
||||
"y": |source_sidebar_title_y| + |source_sidebar_title_height| + 6,
|
||||
|
@ -202,16 +189,10 @@ set-window-size: (450, 700)
|
|||
assert-css: ("nav.sub", {"flex-direction": "column"})
|
||||
|
||||
// Check the sidebar directory entries have a marker and spacing (phone).
|
||||
store-property: (
|
||||
source_sidebar_title_height,
|
||||
"#source-sidebar > .title",
|
||||
"offsetHeight"
|
||||
)
|
||||
store-property: (
|
||||
source_sidebar_title_y,
|
||||
"#source-sidebar > .title",
|
||||
"offsetTop"
|
||||
)
|
||||
store-property: ("#source-sidebar > .title", {
|
||||
"offsetHeight": source_sidebar_title_height,
|
||||
"offsetTop": source_sidebar_title_y,
|
||||
})
|
||||
call-function: ("check-sidebar-dir-entry", {
|
||||
"x": 0,
|
||||
"y": |source_sidebar_title_y| + |source_sidebar_title_height| + 6,
|
||||
|
@ -219,5 +200,5 @@ call-function: ("check-sidebar-dir-entry", {
|
|||
|
||||
// Now we check that the logo has a bottom margin so it's not stuck to the search input.
|
||||
assert-css: (".sub-logo-container > img", {"margin-bottom": "8px"})
|
||||
store-property: (logo_height, ".sub-logo-container", "clientHeight")
|
||||
store-property: (".sub-logo-container", {"clientHeight": logo_height})
|
||||
assert-position: (".search-form", {"y": |logo_height| + 8})
|
||||
|
|
|
@ -11,6 +11,6 @@ assert-css: (".impl-items .srclink", {"font-size": "16px", "font-weight": 400},
|
|||
assert-css: (".impl-items .code-header", {"font-size": "16px", "font-weight": 600}, ALL)
|
||||
|
||||
// Check that we can click on source link
|
||||
store-document-property: (url, "URL")
|
||||
store-document-property: {"URL": url}
|
||||
click: ".impl-items .srclink"
|
||||
assert-document-property-false: {"URL": |url|}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// This test ensures that each field is on its own line (In other words, they have display: block).
|
||||
go-to: "file://" + |DOC_PATH| + "/test_docs/struct.StructWithPublicUndocumentedFields.html"
|
||||
|
||||
store-property: (first_top, "//*[@id='structfield.first']", "offsetTop")
|
||||
store-property: ("//*[@id='structfield.first']", {"offsetTop": first_top})
|
||||
assert-property-false: ("//*[@id='structfield.second']", { "offsetTop": |first_top| })
|
||||
|
|
|
@ -39,7 +39,7 @@ assert-property: ("pre.item-decl", {"scrollWidth": "950"})
|
|||
set-window-size: (600, 600)
|
||||
go-to: "file://" + |DOC_PATH| + "/lib2/too_long/struct.SuperIncrediblyLongLongLongLongLongLongLongGigaGigaGigaMegaLongLongLongStructName.html"
|
||||
// It shouldn't have an overflow in the topbar either.
|
||||
store-property: (scrollWidth, ".mobile-topbar h2", "scrollWidth")
|
||||
store-property: (".mobile-topbar h2", {"scrollWidth": scrollWidth})
|
||||
assert-property: (".mobile-topbar h2", {"clientWidth": |scrollWidth|})
|
||||
assert-css: (".mobile-topbar h2", {"overflow-x": "hidden"})
|
||||
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
// normalize-stderr-test "note: compiler flags.*\n\n" -> ""
|
||||
// normalize-stderr-test "note: rustc.*running on.*" -> "note: rustc {version} running on {platform}"
|
||||
// normalize-stderr-test "thread.*panicked at .*, compiler.*" -> "thread panicked at 'aborting due to `-Z treat-err-as-bug`'"
|
||||
// normalize-stderr-test "\s*\d{1,}: .*\n" -> ""
|
||||
// normalize-stderr-test "\s at .*\n" -> ""
|
||||
// normalize-stderr-test " +\d{1,}: .*\n" -> ""
|
||||
// normalize-stderr-test " + at .*\n" -> ""
|
||||
// normalize-stderr-test ".*note: Some details are omitted.*\n" -> ""
|
||||
|
||||
fn wrong()
|
||||
|
|
|
@ -6,6 +6,7 @@ LL | fn wrong()
|
|||
|
||||
thread panicked at 'aborting due to `-Z treat-err-as-bug`'
|
||||
stack backtrace:
|
||||
|
||||
error: the compiler unexpectedly panicked. this is a bug.
|
||||
|
||||
note: we would appreciate a bug report: https://github.com/rust-lang/rust/issues/new?labels=C-bug%2C+I-ICE%2C+T-rustdoc&template=ice.md
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#![feature(inherent_associated_types)]
|
||||
#![allow(incomplete_features)]
|
||||
#![deny(single_use_lifetimes)]
|
||||
|
||||
struct Foo<T>(T);
|
||||
|
||||
|
|
8
tests/ui/resolve/explicit-self-lowercase-param.rs
Normal file
8
tests/ui/resolve/explicit-self-lowercase-param.rs
Normal file
|
@ -0,0 +1,8 @@
|
|||
struct Foo;
|
||||
|
||||
impl Foo {
|
||||
fn do_nothing(self: Box<self>) {} //~ ERROR attempt to use a non-constant value in a constant
|
||||
//~^ HELP try using `Self`
|
||||
}
|
||||
|
||||
fn main() {}
|
8
tests/ui/resolve/explicit-self-lowercase-param.stderr
Normal file
8
tests/ui/resolve/explicit-self-lowercase-param.stderr
Normal file
|
@ -0,0 +1,8 @@
|
|||
error: attempt to use a non-constant value in a constant
|
||||
--> $DIR/explicit-self-lowercase-param.rs:4:29
|
||||
|
|
||||
LL | fn do_nothing(self: Box<self>) {}
|
||||
| ^^^^ help: try using `Self`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
error[E0309]: the parameter type `T` may not live long enough
|
||||
--> $DIR/wf-in-associated-type.rs:36:23
|
||||
|
|
||||
LL | type Opaque = impl Sized + 'a;
|
||||
| ^^^^^^^^^^^^^^^ ...so that the type `&'a T` will meet its required lifetime bounds
|
||||
|
|
||||
help: consider adding an explicit lifetime bound...
|
||||
|
|
||||
LL | impl<'a, T: 'a> Trait<'a, T> for () {
|
||||
| ++++
|
||||
|
||||
error[E0309]: the parameter type `T` may not live long enough
|
||||
--> $DIR/wf-in-associated-type.rs:36:23
|
||||
|
|
||||
LL | type Opaque = impl Sized + 'a;
|
||||
| ^^^^^^^^^^^^^^^ ...so that the reference type `&'a T` does not outlive the data it points at
|
||||
|
|
||||
help: consider adding an explicit lifetime bound...
|
||||
|
|
||||
LL | impl<'a, T: 'a> Trait<'a, T> for () {
|
||||
| ++++
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0309`.
|
45
tests/ui/type-alias-impl-trait/wf-in-associated-type.rs
Normal file
45
tests/ui/type-alias-impl-trait/wf-in-associated-type.rs
Normal file
|
@ -0,0 +1,45 @@
|
|||
// WF check for impl Trait in associated type position.
|
||||
//
|
||||
// revisions: pass fail
|
||||
// [pass] check-pass
|
||||
// [fail] check-fail
|
||||
|
||||
#![feature(impl_trait_in_assoc_type)]
|
||||
|
||||
// The hidden type here (`&'a T`) requires proving `T: 'a`.
|
||||
// We know it holds because of implied bounds from the impl header.
|
||||
#[cfg(pass)]
|
||||
mod pass {
|
||||
trait Trait<Req> {
|
||||
type Opaque1;
|
||||
fn constrain_opaque1(req: Req) -> Self::Opaque1;
|
||||
}
|
||||
|
||||
impl<'a, T> Trait<&'a T> for () {
|
||||
type Opaque1 = impl IntoIterator<Item = impl Sized + 'a>;
|
||||
fn constrain_opaque1(req: &'a T) -> Self::Opaque1 {
|
||||
[req]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The hidden type here (`&'a T`) requires proving `T: 'a`,
|
||||
// but that is not known to hold in the impl.
|
||||
#[cfg(fail)]
|
||||
mod fail {
|
||||
trait Trait<'a, T> {
|
||||
type Opaque;
|
||||
fn constrain_opaque(req: &'a T) -> Self::Opaque;
|
||||
}
|
||||
|
||||
impl<'a, T> Trait<'a, T> for () {
|
||||
type Opaque = impl Sized + 'a;
|
||||
//[fail]~^ ERROR the parameter type `T` may not live long enough
|
||||
//[fail]~| ERROR the parameter type `T` may not live long enough
|
||||
fn constrain_opaque(req: &'a T) -> Self::Opaque {
|
||||
req
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
19
tests/ui/type-alias-impl-trait/wf-nested.fail.stderr
Normal file
19
tests/ui/type-alias-impl-trait/wf-nested.fail.stderr
Normal file
|
@ -0,0 +1,19 @@
|
|||
error[E0310]: the parameter type `T` may not live long enough
|
||||
--> $DIR/wf-nested.rs:55:27
|
||||
|
|
||||
LL | type InnerOpaque<T> = impl Sized;
|
||||
| ^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds...
|
||||
|
|
||||
note: ...that is required by this bound
|
||||
--> $DIR/wf-nested.rs:12:20
|
||||
|
|
||||
LL | struct IsStatic<T: 'static>(T);
|
||||
| ^^^^^^^
|
||||
help: consider adding an explicit lifetime bound...
|
||||
|
|
||||
LL | type InnerOpaque<T: 'static> = impl Sized;
|
||||
| +++++++++
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0310`.
|
14
tests/ui/type-alias-impl-trait/wf-nested.pass_sound.stderr
Normal file
14
tests/ui/type-alias-impl-trait/wf-nested.pass_sound.stderr
Normal file
|
@ -0,0 +1,14 @@
|
|||
error[E0310]: the parameter type `T` may not live long enough
|
||||
--> $DIR/wf-nested.rs:46:17
|
||||
|
|
||||
LL | let _ = outer.get();
|
||||
| ^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
|
||||
|
|
||||
help: consider adding an explicit lifetime bound...
|
||||
|
|
||||
LL | fn test<T: 'static>() {
|
||||
| +++++++++
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0310`.
|
60
tests/ui/type-alias-impl-trait/wf-nested.rs
Normal file
60
tests/ui/type-alias-impl-trait/wf-nested.rs
Normal file
|
@ -0,0 +1,60 @@
|
|||
// Well-formedness of nested opaque types, i.e. `impl Sized` in
|
||||
// `type Outer = impl Trait<Assoc = impl Sized>`.
|
||||
// See the comments below.
|
||||
//
|
||||
// revisions: pass pass_sound fail
|
||||
// [pass] check-pass
|
||||
// [pass_sound] check-fail
|
||||
// [fail] check-fail
|
||||
|
||||
#![feature(type_alias_impl_trait)]
|
||||
|
||||
struct IsStatic<T: 'static>(T);
|
||||
|
||||
trait Trait<In> {
|
||||
type Out;
|
||||
|
||||
fn get(&self) -> Result<Self::Out, ()> {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Trait<&'static T> for () {
|
||||
type Out = IsStatic<T>;
|
||||
}
|
||||
|
||||
// The hidden type for `impl Sized` is `IsStatic<T>`, which requires `T: 'static`.
|
||||
// We know it is well-formed because it can *only* be referenced as a projection:
|
||||
// <OuterOpaque<T> as Trait<&'static T>>::Out`.
|
||||
// So any instantiation of the type already requires proving `T: 'static`.
|
||||
#[cfg(pass)]
|
||||
mod pass {
|
||||
use super::*;
|
||||
type OuterOpaque<T> = impl Trait<&'static T, Out = impl Sized>;
|
||||
fn define<T>() -> OuterOpaque<T> {}
|
||||
}
|
||||
|
||||
// Test the soundness of `pass` - We should require `T: 'static` at the use site.
|
||||
#[cfg(pass_sound)]
|
||||
mod pass_sound {
|
||||
use super::*;
|
||||
type OuterOpaque<T> = impl Trait<&'static T, Out = impl Sized>;
|
||||
fn define<T>() -> OuterOpaque<T> {}
|
||||
|
||||
fn test<T>() {
|
||||
let outer = define::<T>();
|
||||
let _ = outer.get(); //[pass_sound]~ ERROR `T` may not live long enough
|
||||
}
|
||||
}
|
||||
|
||||
// Similar to `pass` but here `impl Sized` can be referenced directly as
|
||||
// InnerOpaque<T>, so we require an explicit bound `T: 'static`.
|
||||
#[cfg(fail)]
|
||||
mod fail {
|
||||
use super::*;
|
||||
type InnerOpaque<T> = impl Sized; //[fail]~ ERROR `T` may not live long enough
|
||||
type OuterOpaque<T> = impl Trait<&'static T, Out = InnerOpaque<T>>;
|
||||
fn define<T>() -> OuterOpaque<T> {}
|
||||
}
|
||||
|
||||
fn main() {}
|
Loading…
Add table
Reference in a new issue