mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 14:55:26 +00:00
Auto merge of #100809 - matthiaskrgr:rollup-xkpd5ii, r=matthiaskrgr
Rollup of 9 pull requests Successful merges: - #99415 (Initial implementation of REUSE) - #99544 (Expose `Utf8Lossy` as `Utf8Chunks`) - #100585 (Fix trailing space showing up in example) - #100596 (Remove unnecessary stderr files) - #100642 (Update fortanix-sgx-abi and export some useful SGX usercall traits) - #100691 (Make `same_type_modulo_infer` a proper `TypeRelation`) - #100693 (Add LLVM15-specific codegen test for `try`/`?`s that now optimize away) - #100710 (Windows: Load synch functions together) - #100807 (Add TaKO8Ki to translation-related mention groups) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
48853a361a
28
.reuse/dep5
Normal file
28
.reuse/dep5
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
|
||||||
|
Files-Excluded:
|
||||||
|
src/llvm-project
|
||||||
|
|
||||||
|
Files: *
|
||||||
|
Copyright: The Rust Project Developers (see https://thanks.rust-lang.org)
|
||||||
|
License: MIT or Apache-2.0
|
||||||
|
|
||||||
|
Files: library/std/src/sync/mpsc/mpsc_queue.rs
|
||||||
|
library/std/src/sync/mpsc/spsc_queue.rs
|
||||||
|
Copyright: 2010-2011 Dmitry Vyukov
|
||||||
|
License: BSD-2-Clause
|
||||||
|
|
||||||
|
Files: src/librustdoc/html/static/fonts/FiraSans*
|
||||||
|
Copyright: 2014, Mozilla Foundation, 2014, Telefonica S.A.
|
||||||
|
License: OFL-1.1
|
||||||
|
|
||||||
|
Files: src/librustdoc/html/static/fonts/NanumBarun*
|
||||||
|
Copyright: 2010 NAVER Corporation
|
||||||
|
License: OFL-1.1
|
||||||
|
|
||||||
|
Files: src/librustdoc/html/static/fonts/SourceCodePro*
|
||||||
|
Copyright: 2010, 2012 Adobe Systems Incorporated
|
||||||
|
License: OFL-1.1
|
||||||
|
|
||||||
|
Files: src/librustdoc/html/static/fonts/SourceSerif4*
|
||||||
|
Copyright: 2014-2021 Adobe Systems Incorporated
|
||||||
|
License: OFL-1.1
|
@ -1421,9 +1421,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fortanix-sgx-abi"
|
name = "fortanix-sgx-abi"
|
||||||
version = "0.3.3"
|
version = "0.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c56c422ef86062869b2d57ae87270608dc5929969dd130a6e248979cf4fb6ca6"
|
checksum = "57cafc2274c10fab234f176b25903ce17e690fca7597090d50880e047a0389c5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"compiler_builtins",
|
"compiler_builtins",
|
||||||
"rustc-std-workspace-core",
|
"rustc-std-workspace-core",
|
||||||
|
73
LICENSES/Apache-2.0.txt
Normal file
73
LICENSES/Apache-2.0.txt
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright [yyyy] [name of copyright owner]
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
9
LICENSES/BSD-2-Clause.txt
Normal file
9
LICENSES/BSD-2-Clause.txt
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
Copyright (c) <year> <owner>
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
9
LICENSES/MIT.txt
Normal file
9
LICENSES/MIT.txt
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) <year> <copyright holders>
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
43
LICENSES/OFL-1.1.txt
Normal file
43
LICENSES/OFL-1.1.txt
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
SIL OPEN FONT LICENSE
|
||||||
|
|
||||||
|
Version 1.1 - 26 February 2007
|
||||||
|
|
||||||
|
PREAMBLE
|
||||||
|
|
||||||
|
The goals of the Open Font License (OFL) are to stimulate worldwide development of collaborative font projects, to support the font creation efforts of academic and linguistic communities, and to provide a free and open framework in which fonts may be shared and improved in partnership with others.
|
||||||
|
|
||||||
|
The OFL allows the licensed fonts to be used, studied, modified and redistributed freely as long as they are not sold by themselves. The fonts, including any derivative works, can be bundled, embedded, redistributed and/or sold with any software provided that any reserved names are not used by derivative works. The fonts and derivatives, however, cannot be released under any other type of license. The requirement for fonts to remain under this license does not apply to any document created using the fonts or their derivatives.
|
||||||
|
|
||||||
|
DEFINITIONS
|
||||||
|
|
||||||
|
"Font Software" refers to the set of files released by the Copyright Holder(s) under this license and clearly marked as such. This may include source files, build scripts and documentation.
|
||||||
|
|
||||||
|
"Reserved Font Name" refers to any names specified as such after the copyright statement(s).
|
||||||
|
|
||||||
|
"Original Version" refers to the collection of Font Software components as distributed by the Copyright Holder(s).
|
||||||
|
|
||||||
|
"Modified Version" refers to any derivative made by adding to, deleting, or substituting — in part or in whole — any of the components of the Original Version, by changing formats or by porting the Font Software to a new environment.
|
||||||
|
|
||||||
|
"Author" refers to any designer, engineer, programmer, technical writer or other person who contributed to the Font Software.
|
||||||
|
|
||||||
|
PERMISSION & CONDITIONS
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of the Font Software, to use, study, copy, merge, embed, modify, redistribute, and sell modified and unmodified copies of the Font Software, subject to the following conditions:
|
||||||
|
|
||||||
|
1) Neither the Font Software nor any of its individual components, in Original or Modified Versions, may be sold by itself.
|
||||||
|
|
||||||
|
2) Original or Modified Versions of the Font Software may be bundled, redistributed and/or sold with any software, provided that each copy contains the above copyright notice and this license. These can be included either as stand-alone text files, human-readable headers or in the appropriate machine-readable metadata fields within text or binary files as long as those fields can be easily viewed by the user.
|
||||||
|
|
||||||
|
3) No Modified Version of the Font Software may use the Reserved Font Name(s) unless explicit written permission is granted by the corresponding Copyright Holder. This restriction only applies to the primary font name as presented to the users.
|
||||||
|
|
||||||
|
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font Software shall not be used to promote, endorse or advertise any Modified Version, except to acknowledge the contribution(s) of the Copyright Holder(s) and the Author(s) or with their explicit written permission.
|
||||||
|
|
||||||
|
5) The Font Software, modified or unmodified, in part or in whole, must be distributed entirely under this license, and must not be distributed under any other license. The requirement for fonts to remain under this license does not apply to any document created using the Font Software.
|
||||||
|
|
||||||
|
TERMINATION
|
||||||
|
|
||||||
|
This license becomes null and void if any of the above conditions are not met.
|
||||||
|
|
||||||
|
DISCLAIMER
|
||||||
|
|
||||||
|
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE.
|
@ -66,6 +66,7 @@ use rustc_hir::lang_items::LangItem;
|
|||||||
use rustc_hir::Node;
|
use rustc_hir::Node;
|
||||||
use rustc_middle::dep_graph::DepContext;
|
use rustc_middle::dep_graph::DepContext;
|
||||||
use rustc_middle::ty::print::with_no_trimmed_paths;
|
use rustc_middle::ty::print::with_no_trimmed_paths;
|
||||||
|
use rustc_middle::ty::relate::{self, RelateResult, TypeRelation};
|
||||||
use rustc_middle::ty::{
|
use rustc_middle::ty::{
|
||||||
self, error::TypeError, Binder, List, Region, Subst, Ty, TyCtxt, TypeFoldable,
|
self, error::TypeError, Binder, List, Region, Subst, Ty, TyCtxt, TypeFoldable,
|
||||||
TypeSuperVisitable, TypeVisitable,
|
TypeSuperVisitable, TypeVisitable,
|
||||||
@ -2661,67 +2662,92 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||||||
/// Float types, respectively). When comparing two ADTs, these rules apply recursively.
|
/// Float types, respectively). When comparing two ADTs, these rules apply recursively.
|
||||||
pub fn same_type_modulo_infer(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> bool {
|
pub fn same_type_modulo_infer(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> bool {
|
||||||
let (a, b) = self.resolve_vars_if_possible((a, b));
|
let (a, b) = self.resolve_vars_if_possible((a, b));
|
||||||
|
SameTypeModuloInfer(self).relate(a, b).is_ok()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct SameTypeModuloInfer<'a, 'tcx>(&'a InferCtxt<'a, 'tcx>);
|
||||||
|
|
||||||
|
impl<'tcx> TypeRelation<'tcx> for SameTypeModuloInfer<'_, 'tcx> {
|
||||||
|
fn tcx(&self) -> TyCtxt<'tcx> {
|
||||||
|
self.0.tcx
|
||||||
|
}
|
||||||
|
|
||||||
|
fn param_env(&self) -> ty::ParamEnv<'tcx> {
|
||||||
|
// Unused, only for consts which we treat as always equal
|
||||||
|
ty::ParamEnv::empty()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn tag(&self) -> &'static str {
|
||||||
|
"SameTypeModuloInfer"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn a_is_expected(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn relate_with_variance<T: relate::Relate<'tcx>>(
|
||||||
|
&mut self,
|
||||||
|
_variance: ty::Variance,
|
||||||
|
_info: ty::VarianceDiagInfo<'tcx>,
|
||||||
|
a: T,
|
||||||
|
b: T,
|
||||||
|
) -> relate::RelateResult<'tcx, T> {
|
||||||
|
self.relate(a, b)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
|
||||||
match (a.kind(), b.kind()) {
|
match (a.kind(), b.kind()) {
|
||||||
(&ty::Adt(def_a, substs_a), &ty::Adt(def_b, substs_b)) => {
|
(ty::Int(_) | ty::Uint(_), ty::Infer(ty::InferTy::IntVar(_)))
|
||||||
if def_a != def_b {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
substs_a
|
|
||||||
.types()
|
|
||||||
.zip(substs_b.types())
|
|
||||||
.all(|(a, b)| self.same_type_modulo_infer(a, b))
|
|
||||||
}
|
|
||||||
(&ty::FnDef(did_a, substs_a), &ty::FnDef(did_b, substs_b)) => {
|
|
||||||
if did_a != did_b {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
substs_a
|
|
||||||
.types()
|
|
||||||
.zip(substs_b.types())
|
|
||||||
.all(|(a, b)| self.same_type_modulo_infer(a, b))
|
|
||||||
}
|
|
||||||
(&ty::Int(_) | &ty::Uint(_), &ty::Infer(ty::InferTy::IntVar(_)))
|
|
||||||
| (
|
| (
|
||||||
&ty::Infer(ty::InferTy::IntVar(_)),
|
ty::Infer(ty::InferTy::IntVar(_)),
|
||||||
&ty::Int(_) | &ty::Uint(_) | &ty::Infer(ty::InferTy::IntVar(_)),
|
ty::Int(_) | ty::Uint(_) | ty::Infer(ty::InferTy::IntVar(_)),
|
||||||
)
|
)
|
||||||
| (&ty::Float(_), &ty::Infer(ty::InferTy::FloatVar(_)))
|
| (ty::Float(_), ty::Infer(ty::InferTy::FloatVar(_)))
|
||||||
| (
|
| (
|
||||||
&ty::Infer(ty::InferTy::FloatVar(_)),
|
ty::Infer(ty::InferTy::FloatVar(_)),
|
||||||
&ty::Float(_) | &ty::Infer(ty::InferTy::FloatVar(_)),
|
ty::Float(_) | ty::Infer(ty::InferTy::FloatVar(_)),
|
||||||
)
|
)
|
||||||
| (&ty::Infer(ty::InferTy::TyVar(_)), _)
|
| (ty::Infer(ty::InferTy::TyVar(_)), _)
|
||||||
| (_, &ty::Infer(ty::InferTy::TyVar(_))) => true,
|
| (_, ty::Infer(ty::InferTy::TyVar(_))) => Ok(a),
|
||||||
(&ty::Ref(_, ty_a, mut_a), &ty::Ref(_, ty_b, mut_b)) => {
|
(ty::Infer(_), _) | (_, ty::Infer(_)) => Err(TypeError::Mismatch),
|
||||||
mut_a == mut_b && self.same_type_modulo_infer(ty_a, ty_b)
|
_ => relate::super_relate_tys(self, a, b),
|
||||||
}
|
|
||||||
(&ty::RawPtr(a), &ty::RawPtr(b)) => {
|
|
||||||
a.mutbl == b.mutbl && self.same_type_modulo_infer(a.ty, b.ty)
|
|
||||||
}
|
|
||||||
(&ty::Slice(a), &ty::Slice(b)) => self.same_type_modulo_infer(a, b),
|
|
||||||
(&ty::Array(a_ty, a_ct), &ty::Array(b_ty, b_ct)) => {
|
|
||||||
self.same_type_modulo_infer(a_ty, b_ty) && a_ct == b_ct
|
|
||||||
}
|
|
||||||
(&ty::Tuple(a), &ty::Tuple(b)) => {
|
|
||||||
if a.len() != b.len() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
std::iter::zip(a.iter(), b.iter()).all(|(a, b)| self.same_type_modulo_infer(a, b))
|
|
||||||
}
|
|
||||||
(&ty::FnPtr(a), &ty::FnPtr(b)) => {
|
|
||||||
let a = a.skip_binder().inputs_and_output;
|
|
||||||
let b = b.skip_binder().inputs_and_output;
|
|
||||||
if a.len() != b.len() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
std::iter::zip(a.iter(), b.iter()).all(|(a, b)| self.same_type_modulo_infer(a, b))
|
|
||||||
}
|
|
||||||
// FIXME(compiler-errors): This needs to be generalized more
|
|
||||||
_ => a == b,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn regions(
|
||||||
|
&mut self,
|
||||||
|
a: ty::Region<'tcx>,
|
||||||
|
b: ty::Region<'tcx>,
|
||||||
|
) -> RelateResult<'tcx, ty::Region<'tcx>> {
|
||||||
|
if (a.is_var() && b.is_free_or_static()) || (b.is_var() && a.is_free_or_static()) || a == b
|
||||||
|
{
|
||||||
|
Ok(a)
|
||||||
|
} else {
|
||||||
|
Err(TypeError::Mismatch)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn binders<T>(
|
||||||
|
&mut self,
|
||||||
|
a: ty::Binder<'tcx, T>,
|
||||||
|
b: ty::Binder<'tcx, T>,
|
||||||
|
) -> relate::RelateResult<'tcx, ty::Binder<'tcx, T>>
|
||||||
|
where
|
||||||
|
T: relate::Relate<'tcx>,
|
||||||
|
{
|
||||||
|
Ok(ty::Binder::dummy(self.relate(a.skip_binder(), b.skip_binder())?))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn consts(
|
||||||
|
&mut self,
|
||||||
|
a: ty::Const<'tcx>,
|
||||||
|
_b: ty::Const<'tcx>,
|
||||||
|
) -> relate::RelateResult<'tcx, ty::Const<'tcx>> {
|
||||||
|
// FIXME(compiler-errors): This could at least do some first-order
|
||||||
|
// relation
|
||||||
|
Ok(a)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||||
|
@ -1617,6 +1617,10 @@ impl<'tcx> Region<'tcx> {
|
|||||||
_ => self.is_free(),
|
_ => self.is_free(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_var(self) -> bool {
|
||||||
|
matches!(self.kind(), ty::ReVar(_))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Type utilities
|
/// Type utilities
|
||||||
|
@ -145,6 +145,7 @@
|
|||||||
#![feature(unchecked_math)]
|
#![feature(unchecked_math)]
|
||||||
#![feature(unicode_internals)]
|
#![feature(unicode_internals)]
|
||||||
#![feature(unsize)]
|
#![feature(unsize)]
|
||||||
|
#![feature(utf8_chunks)]
|
||||||
#![feature(std_internals)]
|
#![feature(std_internals)]
|
||||||
//
|
//
|
||||||
// Language features:
|
// Language features:
|
||||||
|
@ -71,6 +71,8 @@ pub use core::str::{RSplit, Split};
|
|||||||
pub use core::str::{RSplitN, SplitN};
|
pub use core::str::{RSplitN, SplitN};
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub use core::str::{RSplitTerminator, SplitTerminator};
|
pub use core::str::{RSplitTerminator, SplitTerminator};
|
||||||
|
#[unstable(feature = "utf8_chunks", issue = "99543")]
|
||||||
|
pub use core::str::{Utf8Chunk, Utf8Chunks};
|
||||||
|
|
||||||
/// Note: `str` in `Concat<str>` is not meaningful here.
|
/// Note: `str` in `Concat<str>` is not meaningful here.
|
||||||
/// This type parameter of the trait only exists to enable another impl.
|
/// This type parameter of the trait only exists to enable another impl.
|
||||||
|
@ -58,9 +58,9 @@ use core::ops::Bound::{Excluded, Included, Unbounded};
|
|||||||
use core::ops::{self, Index, IndexMut, Range, RangeBounds};
|
use core::ops::{self, Index, IndexMut, Range, RangeBounds};
|
||||||
use core::ptr;
|
use core::ptr;
|
||||||
use core::slice;
|
use core::slice;
|
||||||
#[cfg(not(no_global_oom_handling))]
|
|
||||||
use core::str::lossy;
|
|
||||||
use core::str::pattern::Pattern;
|
use core::str::pattern::Pattern;
|
||||||
|
#[cfg(not(no_global_oom_handling))]
|
||||||
|
use core::str::Utf8Chunks;
|
||||||
|
|
||||||
#[cfg(not(no_global_oom_handling))]
|
#[cfg(not(no_global_oom_handling))]
|
||||||
use crate::borrow::{Cow, ToOwned};
|
use crate::borrow::{Cow, ToOwned};
|
||||||
@ -628,11 +628,11 @@ impl String {
|
|||||||
#[cfg(not(no_global_oom_handling))]
|
#[cfg(not(no_global_oom_handling))]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub fn from_utf8_lossy(v: &[u8]) -> Cow<'_, str> {
|
pub fn from_utf8_lossy(v: &[u8]) -> Cow<'_, str> {
|
||||||
let mut iter = lossy::Utf8Lossy::from_bytes(v).chunks();
|
let mut iter = Utf8Chunks::new(v);
|
||||||
|
|
||||||
let first_valid = if let Some(chunk) = iter.next() {
|
let first_valid = if let Some(chunk) = iter.next() {
|
||||||
let lossy::Utf8LossyChunk { valid, broken } = chunk;
|
let valid = chunk.valid();
|
||||||
if broken.is_empty() {
|
if chunk.invalid().is_empty() {
|
||||||
debug_assert_eq!(valid.len(), v.len());
|
debug_assert_eq!(valid.len(), v.len());
|
||||||
return Cow::Borrowed(valid);
|
return Cow::Borrowed(valid);
|
||||||
}
|
}
|
||||||
@ -647,9 +647,9 @@ impl String {
|
|||||||
res.push_str(first_valid);
|
res.push_str(first_valid);
|
||||||
res.push_str(REPLACEMENT);
|
res.push_str(REPLACEMENT);
|
||||||
|
|
||||||
for lossy::Utf8LossyChunk { valid, broken } in iter {
|
for chunk in iter {
|
||||||
res.push_str(valid);
|
res.push_str(chunk.valid());
|
||||||
if !broken.is_empty() {
|
if !chunk.invalid().is_empty() {
|
||||||
res.push_str(REPLACEMENT);
|
res.push_str(REPLACEMENT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -623,7 +623,7 @@ impl u8 {
|
|||||||
///
|
///
|
||||||
/// - U+0021 ..= U+002F `! " # $ % & ' ( ) * + , - . /`, or
|
/// - U+0021 ..= U+002F `! " # $ % & ' ( ) * + , - . /`, or
|
||||||
/// - U+003A ..= U+0040 `: ; < = > ? @`, or
|
/// - U+003A ..= U+0040 `: ; < = > ? @`, or
|
||||||
/// - U+005B ..= U+0060 ``[ \ ] ^ _ ` ``, or
|
/// - U+005B ..= U+0060 `` [ \ ] ^ _ ` ``, or
|
||||||
/// - U+007B ..= U+007E `{ | } ~`
|
/// - U+007B ..= U+007E `{ | } ~`
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
|
@ -1,51 +1,170 @@
|
|||||||
use crate::char;
|
use crate::fmt;
|
||||||
use crate::fmt::{self, Write};
|
use crate::fmt::Formatter;
|
||||||
use crate::mem;
|
use crate::fmt::Write;
|
||||||
|
use crate::iter::FusedIterator;
|
||||||
|
|
||||||
use super::from_utf8_unchecked;
|
use super::from_utf8_unchecked;
|
||||||
use super::validations::utf8_char_width;
|
use super::validations::utf8_char_width;
|
||||||
|
|
||||||
/// Lossy UTF-8 string.
|
/// An item returned by the [`Utf8Chunks`] iterator.
|
||||||
#[unstable(feature = "str_internals", issue = "none")]
|
///
|
||||||
pub struct Utf8Lossy {
|
/// A `Utf8Chunk` stores a sequence of [`u8`] up to the first broken character
|
||||||
bytes: [u8],
|
/// when decoding a UTF-8 string.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// #![feature(utf8_chunks)]
|
||||||
|
///
|
||||||
|
/// use std::str::Utf8Chunks;
|
||||||
|
///
|
||||||
|
/// // An invalid UTF-8 string
|
||||||
|
/// let bytes = b"foo\xF1\x80bar";
|
||||||
|
///
|
||||||
|
/// // Decode the first `Utf8Chunk`
|
||||||
|
/// let chunk = Utf8Chunks::new(bytes).next().unwrap();
|
||||||
|
///
|
||||||
|
/// // The first three characters are valid UTF-8
|
||||||
|
/// assert_eq!("foo", chunk.valid());
|
||||||
|
///
|
||||||
|
/// // The fourth character is broken
|
||||||
|
/// assert_eq!(b"\xF1\x80", chunk.invalid());
|
||||||
|
/// ```
|
||||||
|
#[unstable(feature = "utf8_chunks", issue = "99543")]
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
|
pub struct Utf8Chunk<'a> {
|
||||||
|
valid: &'a str,
|
||||||
|
invalid: &'a [u8],
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Utf8Lossy {
|
impl<'a> Utf8Chunk<'a> {
|
||||||
|
/// Returns the next validated UTF-8 substring.
|
||||||
|
///
|
||||||
|
/// This substring can be empty at the start of the string or between
|
||||||
|
/// broken UTF-8 characters.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn from_bytes(bytes: &[u8]) -> &Utf8Lossy {
|
#[unstable(feature = "utf8_chunks", issue = "99543")]
|
||||||
// SAFETY: Both use the same memory layout, and UTF-8 correctness isn't required.
|
pub fn valid(&self) -> &'a str {
|
||||||
unsafe { mem::transmute(bytes) }
|
self.valid
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn chunks(&self) -> Utf8LossyChunksIter<'_> {
|
/// Returns the invalid sequence that caused a failure.
|
||||||
Utf8LossyChunksIter { source: &self.bytes }
|
///
|
||||||
|
/// The returned slice will have a maximum length of 3 and starts after the
|
||||||
|
/// substring given by [`valid`]. Decoding will resume after this sequence.
|
||||||
|
///
|
||||||
|
/// If empty, this is the last chunk in the string. If non-empty, an
|
||||||
|
/// unexpected byte was encountered or the end of the input was reached
|
||||||
|
/// unexpectedly.
|
||||||
|
///
|
||||||
|
/// Lossy decoding would replace this sequence with [`U+FFFD REPLACEMENT
|
||||||
|
/// CHARACTER`].
|
||||||
|
///
|
||||||
|
/// [`valid`]: Self::valid
|
||||||
|
/// [`U+FFFD REPLACEMENT CHARACTER`]: crate::char::REPLACEMENT_CHARACTER
|
||||||
|
#[must_use]
|
||||||
|
#[unstable(feature = "utf8_chunks", issue = "99543")]
|
||||||
|
pub fn invalid(&self) -> &'a [u8] {
|
||||||
|
self.invalid
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Iterator over lossy UTF-8 string
|
#[must_use]
|
||||||
#[must_use = "iterators are lazy and do nothing unless consumed"]
|
|
||||||
#[unstable(feature = "str_internals", issue = "none")]
|
#[unstable(feature = "str_internals", issue = "none")]
|
||||||
#[allow(missing_debug_implementations)]
|
pub struct Debug<'a>(&'a [u8]);
|
||||||
pub struct Utf8LossyChunksIter<'a> {
|
|
||||||
|
#[unstable(feature = "str_internals", issue = "none")]
|
||||||
|
impl fmt::Debug for Debug<'_> {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
|
f.write_char('"')?;
|
||||||
|
|
||||||
|
for chunk in Utf8Chunks::new(self.0) {
|
||||||
|
// Valid part.
|
||||||
|
// Here we partially parse UTF-8 again which is suboptimal.
|
||||||
|
{
|
||||||
|
let valid = chunk.valid();
|
||||||
|
let mut from = 0;
|
||||||
|
for (i, c) in valid.char_indices() {
|
||||||
|
let esc = c.escape_debug();
|
||||||
|
// If char needs escaping, flush backlog so far and write, else skip
|
||||||
|
if esc.len() != 1 {
|
||||||
|
f.write_str(&valid[from..i])?;
|
||||||
|
for c in esc {
|
||||||
|
f.write_char(c)?;
|
||||||
|
}
|
||||||
|
from = i + c.len_utf8();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
f.write_str(&valid[from..])?;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Broken parts of string as hex escape.
|
||||||
|
for &b in chunk.invalid() {
|
||||||
|
write!(f, "\\x{:02X}", b)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
f.write_char('"')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An iterator used to decode a slice of mostly UTF-8 bytes to string slices
|
||||||
|
/// ([`&str`]) and byte slices ([`&[u8]`][byteslice]).
|
||||||
|
///
|
||||||
|
/// If you want a simple conversion from UTF-8 byte slices to string slices,
|
||||||
|
/// [`from_utf8`] is easier to use.
|
||||||
|
///
|
||||||
|
/// [byteslice]: slice
|
||||||
|
/// [`from_utf8`]: super::from_utf8
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// This can be used to create functionality similar to
|
||||||
|
/// [`String::from_utf8_lossy`] without allocating heap memory:
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// #![feature(utf8_chunks)]
|
||||||
|
///
|
||||||
|
/// use std::str::Utf8Chunks;
|
||||||
|
///
|
||||||
|
/// fn from_utf8_lossy<F>(input: &[u8], mut push: F) where F: FnMut(&str) {
|
||||||
|
/// for chunk in Utf8Chunks::new(input) {
|
||||||
|
/// push(chunk.valid());
|
||||||
|
///
|
||||||
|
/// if !chunk.invalid().is_empty() {
|
||||||
|
/// push("\u{FFFD}");
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// [`String::from_utf8_lossy`]: ../../std/string/struct.String.html#method.from_utf8_lossy
|
||||||
|
#[must_use = "iterators are lazy and do nothing unless consumed"]
|
||||||
|
#[unstable(feature = "utf8_chunks", issue = "99543")]
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct Utf8Chunks<'a> {
|
||||||
source: &'a [u8],
|
source: &'a [u8],
|
||||||
}
|
}
|
||||||
|
|
||||||
#[unstable(feature = "str_internals", issue = "none")]
|
impl<'a> Utf8Chunks<'a> {
|
||||||
#[derive(PartialEq, Eq, Debug)]
|
/// Creates a new iterator to decode the bytes.
|
||||||
pub struct Utf8LossyChunk<'a> {
|
#[unstable(feature = "utf8_chunks", issue = "99543")]
|
||||||
/// Sequence of valid chars.
|
pub fn new(bytes: &'a [u8]) -> Self {
|
||||||
/// Can be empty between broken UTF-8 chars.
|
Self { source: bytes }
|
||||||
pub valid: &'a str,
|
}
|
||||||
/// Single broken char, empty if none.
|
|
||||||
/// Empty iff iterator item is last.
|
#[doc(hidden)]
|
||||||
pub broken: &'a [u8],
|
#[unstable(feature = "str_internals", issue = "none")]
|
||||||
|
pub fn debug(&self) -> Debug<'_> {
|
||||||
|
Debug(self.source)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Iterator for Utf8LossyChunksIter<'a> {
|
#[unstable(feature = "utf8_chunks", issue = "99543")]
|
||||||
type Item = Utf8LossyChunk<'a>;
|
impl<'a> Iterator for Utf8Chunks<'a> {
|
||||||
|
type Item = Utf8Chunk<'a>;
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Utf8LossyChunk<'a>> {
|
fn next(&mut self) -> Option<Utf8Chunk<'a>> {
|
||||||
if self.source.is_empty() {
|
if self.source.is_empty() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
@ -130,71 +249,22 @@ impl<'a> Iterator for Utf8LossyChunksIter<'a> {
|
|||||||
|
|
||||||
// SAFETY: `valid_up_to <= i` because it is only ever assigned via
|
// SAFETY: `valid_up_to <= i` because it is only ever assigned via
|
||||||
// `valid_up_to = i` and `i` only increases.
|
// `valid_up_to = i` and `i` only increases.
|
||||||
let (valid, broken) = unsafe { inspected.split_at_unchecked(valid_up_to) };
|
let (valid, invalid) = unsafe { inspected.split_at_unchecked(valid_up_to) };
|
||||||
|
|
||||||
Some(Utf8LossyChunk {
|
Some(Utf8Chunk {
|
||||||
// SAFETY: All bytes up to `valid_up_to` are valid UTF-8.
|
// SAFETY: All bytes up to `valid_up_to` are valid UTF-8.
|
||||||
valid: unsafe { from_utf8_unchecked(valid) },
|
valid: unsafe { from_utf8_unchecked(valid) },
|
||||||
broken,
|
invalid,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for Utf8Lossy {
|
#[unstable(feature = "utf8_chunks", issue = "99543")]
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
impl FusedIterator for Utf8Chunks<'_> {}
|
||||||
// If we're the empty string then our iterator won't actually yield
|
|
||||||
// anything, so perform the formatting manually
|
|
||||||
if self.bytes.is_empty() {
|
|
||||||
return "".fmt(f);
|
|
||||||
}
|
|
||||||
|
|
||||||
for Utf8LossyChunk { valid, broken } in self.chunks() {
|
#[unstable(feature = "utf8_chunks", issue = "99543")]
|
||||||
// If we successfully decoded the whole chunk as a valid string then
|
impl fmt::Debug for Utf8Chunks<'_> {
|
||||||
// we can return a direct formatting of the string which will also
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
// respect various formatting flags if possible.
|
f.debug_struct("Utf8Chunks").field("source", &self.debug()).finish()
|
||||||
if valid.len() == self.bytes.len() {
|
|
||||||
assert!(broken.is_empty());
|
|
||||||
return valid.fmt(f);
|
|
||||||
}
|
|
||||||
|
|
||||||
f.write_str(valid)?;
|
|
||||||
if !broken.is_empty() {
|
|
||||||
f.write_char(char::REPLACEMENT_CHARACTER)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Debug for Utf8Lossy {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
f.write_char('"')?;
|
|
||||||
|
|
||||||
for Utf8LossyChunk { valid, broken } in self.chunks() {
|
|
||||||
// Valid part.
|
|
||||||
// Here we partially parse UTF-8 again which is suboptimal.
|
|
||||||
{
|
|
||||||
let mut from = 0;
|
|
||||||
for (i, c) in valid.char_indices() {
|
|
||||||
let esc = c.escape_debug();
|
|
||||||
// If char needs escaping, flush backlog so far and write, else skip
|
|
||||||
if esc.len() != 1 {
|
|
||||||
f.write_str(&valid[from..i])?;
|
|
||||||
for c in esc {
|
|
||||||
f.write_char(c)?;
|
|
||||||
}
|
|
||||||
from = i + c.len_utf8();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
f.write_str(&valid[from..])?;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Broken parts of string as hex escape.
|
|
||||||
for &b in broken {
|
|
||||||
write!(f, "\\x{:02x}", b)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
f.write_char('"')
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,9 +22,9 @@ use crate::slice::{self, SliceIndex};
|
|||||||
|
|
||||||
pub mod pattern;
|
pub mod pattern;
|
||||||
|
|
||||||
#[unstable(feature = "str_internals", issue = "none")]
|
mod lossy;
|
||||||
#[allow(missing_docs)]
|
#[unstable(feature = "utf8_chunks", issue = "99543")]
|
||||||
pub mod lossy;
|
pub use lossy::{Utf8Chunk, Utf8Chunks};
|
||||||
|
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub use converts::{from_utf8, from_utf8_unchecked};
|
pub use converts::{from_utf8, from_utf8_unchecked};
|
||||||
|
@ -99,6 +99,7 @@
|
|||||||
#![feature(waker_getters)]
|
#![feature(waker_getters)]
|
||||||
#![feature(slice_flatten)]
|
#![feature(slice_flatten)]
|
||||||
#![feature(provide_any)]
|
#![feature(provide_any)]
|
||||||
|
#![feature(utf8_chunks)]
|
||||||
#![deny(unsafe_op_in_unsafe_fn)]
|
#![deny(unsafe_op_in_unsafe_fn)]
|
||||||
|
|
||||||
extern crate test;
|
extern crate test;
|
||||||
|
@ -1,85 +1,85 @@
|
|||||||
use core::str::lossy::*;
|
use core::str::Utf8Chunks;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn chunks() {
|
fn chunks() {
|
||||||
let mut iter = Utf8Lossy::from_bytes(b"hello").chunks();
|
macro_rules! assert_chunks {
|
||||||
assert_eq!(Some(Utf8LossyChunk { valid: "hello", broken: b"" }), iter.next());
|
( $string:expr, $(($valid:expr, $invalid:expr)),* $(,)? ) => {{
|
||||||
assert_eq!(None, iter.next());
|
let mut iter = Utf8Chunks::new($string);
|
||||||
|
$(
|
||||||
|
let chunk = iter.next().expect("missing chunk");
|
||||||
|
assert_eq!($valid, chunk.valid());
|
||||||
|
assert_eq!($invalid, chunk.invalid());
|
||||||
|
)*
|
||||||
|
assert_eq!(None, iter.next());
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
let mut iter = Utf8Lossy::from_bytes("ศไทย中华Việt Nam".as_bytes()).chunks();
|
assert_chunks!(b"hello", ("hello", b""));
|
||||||
assert_eq!(Some(Utf8LossyChunk { valid: "ศไทย中华Việt Nam", broken: b"" }), iter.next());
|
assert_chunks!("ศไทย中华Việt Nam".as_bytes(), ("ศไทย中华Việt Nam", b""));
|
||||||
assert_eq!(None, iter.next());
|
assert_chunks!(
|
||||||
|
b"Hello\xC2 There\xFF Goodbye",
|
||||||
let mut iter = Utf8Lossy::from_bytes(b"Hello\xC2 There\xFF Goodbye").chunks();
|
("Hello", b"\xC2"),
|
||||||
assert_eq!(Some(Utf8LossyChunk { valid: "Hello", broken: b"\xC2" }), iter.next());
|
(" There", b"\xFF"),
|
||||||
assert_eq!(Some(Utf8LossyChunk { valid: " There", broken: b"\xFF" }), iter.next());
|
(" Goodbye", b""),
|
||||||
assert_eq!(Some(Utf8LossyChunk { valid: " Goodbye", broken: b"" }), iter.next());
|
);
|
||||||
assert_eq!(None, iter.next());
|
assert_chunks!(
|
||||||
|
b"Hello\xC0\x80 There\xE6\x83 Goodbye",
|
||||||
let mut iter = Utf8Lossy::from_bytes(b"Hello\xC0\x80 There\xE6\x83 Goodbye").chunks();
|
("Hello", b"\xC0"),
|
||||||
assert_eq!(Some(Utf8LossyChunk { valid: "Hello", broken: b"\xC0" }), iter.next());
|
("", b"\x80"),
|
||||||
assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\x80" }), iter.next());
|
(" There", b"\xE6\x83"),
|
||||||
assert_eq!(Some(Utf8LossyChunk { valid: " There", broken: b"\xE6\x83" }), iter.next());
|
(" Goodbye", b""),
|
||||||
assert_eq!(Some(Utf8LossyChunk { valid: " Goodbye", broken: b"" }), iter.next());
|
);
|
||||||
assert_eq!(None, iter.next());
|
assert_chunks!(
|
||||||
|
b"\xF5foo\xF5\x80bar",
|
||||||
let mut iter = Utf8Lossy::from_bytes(b"\xF5foo\xF5\x80bar").chunks();
|
("", b"\xF5"),
|
||||||
assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xF5" }), iter.next());
|
("foo", b"\xF5"),
|
||||||
assert_eq!(Some(Utf8LossyChunk { valid: "foo", broken: b"\xF5" }), iter.next());
|
("", b"\x80"),
|
||||||
assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\x80" }), iter.next());
|
("bar", b""),
|
||||||
assert_eq!(Some(Utf8LossyChunk { valid: "bar", broken: b"" }), iter.next());
|
);
|
||||||
assert_eq!(None, iter.next());
|
assert_chunks!(
|
||||||
|
b"\xF1foo\xF1\x80bar\xF1\x80\x80baz",
|
||||||
let mut iter = Utf8Lossy::from_bytes(b"\xF1foo\xF1\x80bar\xF1\x80\x80baz").chunks();
|
("", b"\xF1"),
|
||||||
assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xF1" }), iter.next());
|
("foo", b"\xF1\x80"),
|
||||||
assert_eq!(Some(Utf8LossyChunk { valid: "foo", broken: b"\xF1\x80" }), iter.next());
|
("bar", b"\xF1\x80\x80"),
|
||||||
assert_eq!(Some(Utf8LossyChunk { valid: "bar", broken: b"\xF1\x80\x80" }), iter.next());
|
("baz", b""),
|
||||||
assert_eq!(Some(Utf8LossyChunk { valid: "baz", broken: b"" }), iter.next());
|
);
|
||||||
assert_eq!(None, iter.next());
|
assert_chunks!(
|
||||||
|
b"\xF4foo\xF4\x80bar\xF4\xBFbaz",
|
||||||
let mut iter = Utf8Lossy::from_bytes(b"\xF4foo\xF4\x80bar\xF4\xBFbaz").chunks();
|
("", b"\xF4"),
|
||||||
assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xF4" }), iter.next());
|
("foo", b"\xF4\x80"),
|
||||||
assert_eq!(Some(Utf8LossyChunk { valid: "foo", broken: b"\xF4\x80" }), iter.next());
|
("bar", b"\xF4"),
|
||||||
assert_eq!(Some(Utf8LossyChunk { valid: "bar", broken: b"\xF4" }), iter.next());
|
("", b"\xBF"),
|
||||||
assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xBF" }), iter.next());
|
("baz", b""),
|
||||||
assert_eq!(Some(Utf8LossyChunk { valid: "baz", broken: b"" }), iter.next());
|
);
|
||||||
assert_eq!(None, iter.next());
|
assert_chunks!(
|
||||||
|
b"\xF0\x80\x80\x80foo\xF0\x90\x80\x80bar",
|
||||||
let mut iter = Utf8Lossy::from_bytes(b"\xF0\x80\x80\x80foo\xF0\x90\x80\x80bar").chunks();
|
("", b"\xF0"),
|
||||||
assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xF0" }), iter.next());
|
("", b"\x80"),
|
||||||
assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\x80" }), iter.next());
|
("", b"\x80"),
|
||||||
assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\x80" }), iter.next());
|
("", b"\x80"),
|
||||||
assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\x80" }), iter.next());
|
("foo\u{10000}bar", b""),
|
||||||
assert_eq!(Some(Utf8LossyChunk { valid: "foo\u{10000}bar", broken: b"" }), iter.next());
|
);
|
||||||
assert_eq!(None, iter.next());
|
|
||||||
|
|
||||||
// surrogates
|
// surrogates
|
||||||
let mut iter = Utf8Lossy::from_bytes(b"\xED\xA0\x80foo\xED\xBF\xBFbar").chunks();
|
assert_chunks!(
|
||||||
assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xED" }), iter.next());
|
b"\xED\xA0\x80foo\xED\xBF\xBFbar",
|
||||||
assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xA0" }), iter.next());
|
("", b"\xED"),
|
||||||
assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\x80" }), iter.next());
|
("", b"\xA0"),
|
||||||
assert_eq!(Some(Utf8LossyChunk { valid: "foo", broken: b"\xED" }), iter.next());
|
("", b"\x80"),
|
||||||
assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xBF" }), iter.next());
|
("foo", b"\xED"),
|
||||||
assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xBF" }), iter.next());
|
("", b"\xBF"),
|
||||||
assert_eq!(Some(Utf8LossyChunk { valid: "bar", broken: b"" }), iter.next());
|
("", b"\xBF"),
|
||||||
assert_eq!(None, iter.next());
|
("bar", b""),
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn display() {
|
|
||||||
assert_eq!(
|
|
||||||
"Hello\u{FFFD}\u{FFFD} There\u{FFFD} Goodbye",
|
|
||||||
&Utf8Lossy::from_bytes(b"Hello\xC0\x80 There\xE6\x83 Goodbye").to_string()
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn debug() {
|
fn debug() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
"\"Hello\\xc0\\x80 There\\xe6\\x83 Goodbye\\u{10d4ea}\"",
|
"\"Hello\\xC0\\x80 There\\xE6\\x83 Goodbye\\u{10d4ea}\"",
|
||||||
&format!(
|
&format!(
|
||||||
"{:?}",
|
"{:?}",
|
||||||
Utf8Lossy::from_bytes(b"Hello\xC0\x80 There\xE6\x83 Goodbye\xf4\x8d\x93\xaa")
|
Utf8Chunks::new(b"Hello\xC0\x80 There\xE6\x83 Goodbye\xf4\x8d\x93\xaa").debug(),
|
||||||
)
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -39,7 +39,7 @@ rand = "0.7"
|
|||||||
dlmalloc = { version = "0.2.3", features = ['rustc-dep-of-std'] }
|
dlmalloc = { version = "0.2.3", features = ['rustc-dep-of-std'] }
|
||||||
|
|
||||||
[target.x86_64-fortanix-unknown-sgx.dependencies]
|
[target.x86_64-fortanix-unknown-sgx.dependencies]
|
||||||
fortanix-sgx-abi = { version = "0.3.2", features = ['rustc-dep-of-std'] }
|
fortanix-sgx-abi = { version = "0.5.0", features = ['rustc-dep-of-std'] }
|
||||||
|
|
||||||
[target.'cfg(target_os = "hermit")'.dependencies]
|
[target.'cfg(target_os = "hermit")'.dependencies]
|
||||||
hermit-abi = { version = "0.2.0", features = ['rustc-dep-of-std'] }
|
hermit-abi = { version = "0.2.0", features = ['rustc-dep-of-std'] }
|
||||||
|
@ -258,6 +258,7 @@
|
|||||||
#![feature(staged_api)]
|
#![feature(staged_api)]
|
||||||
#![feature(thread_local)]
|
#![feature(thread_local)]
|
||||||
#![feature(try_blocks)]
|
#![feature(try_blocks)]
|
||||||
|
#![feature(utf8_chunks)]
|
||||||
//
|
//
|
||||||
// Library features (core):
|
// Library features (core):
|
||||||
#![feature(array_error_internals)]
|
#![feature(array_error_internals)]
|
||||||
|
@ -26,6 +26,7 @@ pub mod usercalls {
|
|||||||
free, insecure_time, launch_thread, read, read_alloc, send, wait, write,
|
free, insecure_time, launch_thread, read, read_alloc, send, wait, write,
|
||||||
};
|
};
|
||||||
pub use crate::sys::abi::usercalls::raw::{do_usercall, Usercalls as UsercallNrs};
|
pub use crate::sys::abi::usercalls::raw::{do_usercall, Usercalls as UsercallNrs};
|
||||||
|
pub use crate::sys::abi::usercalls::raw::{Register, RegisterArgument, ReturnValue};
|
||||||
|
|
||||||
// fortanix-sgx-abi re-exports
|
// fortanix-sgx-abi re-exports
|
||||||
pub use crate::sys::abi::usercalls::raw::Error;
|
pub use crate::sys::abi::usercalls::raw::Error;
|
||||||
|
@ -56,6 +56,8 @@ unsafe impl UserSafeSized for Usercall {}
|
|||||||
#[unstable(feature = "sgx_platform", issue = "56975")]
|
#[unstable(feature = "sgx_platform", issue = "56975")]
|
||||||
unsafe impl UserSafeSized for Return {}
|
unsafe impl UserSafeSized for Return {}
|
||||||
#[unstable(feature = "sgx_platform", issue = "56975")]
|
#[unstable(feature = "sgx_platform", issue = "56975")]
|
||||||
|
unsafe impl UserSafeSized for Cancel {}
|
||||||
|
#[unstable(feature = "sgx_platform", issue = "56975")]
|
||||||
unsafe impl<T: UserSafeSized> UserSafeSized for [T; 2] {}
|
unsafe impl<T: UserSafeSized> UserSafeSized for [T; 2] {}
|
||||||
|
|
||||||
/// A type that can be represented in memory as one or more `UserSafeSized`s.
|
/// A type that can be represented in memory as one or more `UserSafeSized`s.
|
||||||
|
@ -292,12 +292,17 @@ fn check_os_error(err: Result) -> i32 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
trait FromSgxResult {
|
/// Translate the raw result of an SGX usercall.
|
||||||
|
#[unstable(feature = "sgx_platform", issue = "56975")]
|
||||||
|
pub trait FromSgxResult {
|
||||||
|
/// Return type
|
||||||
type Return;
|
type Return;
|
||||||
|
|
||||||
|
/// Translate the raw result of an SGX usercall.
|
||||||
fn from_sgx_result(self) -> IoResult<Self::Return>;
|
fn from_sgx_result(self) -> IoResult<Self::Return>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[unstable(feature = "sgx_platform", issue = "56975")]
|
||||||
impl<T> FromSgxResult for (Result, T) {
|
impl<T> FromSgxResult for (Result, T) {
|
||||||
type Return = T;
|
type Return = T;
|
||||||
|
|
||||||
@ -310,6 +315,7 @@ impl<T> FromSgxResult for (Result, T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[unstable(feature = "sgx_platform", issue = "56975")]
|
||||||
impl FromSgxResult for Result {
|
impl FromSgxResult for Result {
|
||||||
type Return = ();
|
type Return = ();
|
||||||
|
|
||||||
|
@ -37,14 +37,23 @@ pub unsafe fn do_usercall(
|
|||||||
(a, b)
|
(a, b)
|
||||||
}
|
}
|
||||||
|
|
||||||
type Register = u64;
|
/// A value passed or returned in a CPU register.
|
||||||
|
#[unstable(feature = "sgx_platform", issue = "56975")]
|
||||||
|
pub type Register = u64;
|
||||||
|
|
||||||
trait RegisterArgument {
|
/// Translate a type from/to Register to be used as an argument.
|
||||||
|
#[unstable(feature = "sgx_platform", issue = "56975")]
|
||||||
|
pub trait RegisterArgument {
|
||||||
|
/// Translate a Register to Self.
|
||||||
fn from_register(_: Register) -> Self;
|
fn from_register(_: Register) -> Self;
|
||||||
|
/// Translate self to a Register.
|
||||||
fn into_register(self) -> Register;
|
fn into_register(self) -> Register;
|
||||||
}
|
}
|
||||||
|
|
||||||
trait ReturnValue {
|
/// Translate a pair of Registers to the raw usercall return value.
|
||||||
|
#[unstable(feature = "sgx_platform", issue = "56975")]
|
||||||
|
pub trait ReturnValue {
|
||||||
|
/// Translate a pair of Registers to the raw usercall return value.
|
||||||
fn from_registers(call: &'static str, regs: (Register, Register)) -> Self;
|
fn from_registers(call: &'static str, regs: (Register, Register)) -> Self;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,6 +77,7 @@ macro_rules! define_usercalls {
|
|||||||
|
|
||||||
macro_rules! define_ra {
|
macro_rules! define_ra {
|
||||||
(< $i:ident > $t:ty) => {
|
(< $i:ident > $t:ty) => {
|
||||||
|
#[unstable(feature = "sgx_platform", issue = "56975")]
|
||||||
impl<$i> RegisterArgument for $t {
|
impl<$i> RegisterArgument for $t {
|
||||||
fn from_register(a: Register) -> Self {
|
fn from_register(a: Register) -> Self {
|
||||||
a as _
|
a as _
|
||||||
@ -78,6 +88,7 @@ macro_rules! define_ra {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
($i:ty as $t:ty) => {
|
($i:ty as $t:ty) => {
|
||||||
|
#[unstable(feature = "sgx_platform", issue = "56975")]
|
||||||
impl RegisterArgument for $t {
|
impl RegisterArgument for $t {
|
||||||
fn from_register(a: Register) -> Self {
|
fn from_register(a: Register) -> Self {
|
||||||
a as $i as _
|
a as $i as _
|
||||||
@ -88,6 +99,7 @@ macro_rules! define_ra {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
($t:ty) => {
|
($t:ty) => {
|
||||||
|
#[unstable(feature = "sgx_platform", issue = "56975")]
|
||||||
impl RegisterArgument for $t {
|
impl RegisterArgument for $t {
|
||||||
fn from_register(a: Register) -> Self {
|
fn from_register(a: Register) -> Self {
|
||||||
a as _
|
a as _
|
||||||
@ -112,6 +124,7 @@ define_ra!(usize as isize);
|
|||||||
define_ra!(<T> *const T);
|
define_ra!(<T> *const T);
|
||||||
define_ra!(<T> *mut T);
|
define_ra!(<T> *mut T);
|
||||||
|
|
||||||
|
#[unstable(feature = "sgx_platform", issue = "56975")]
|
||||||
impl RegisterArgument for bool {
|
impl RegisterArgument for bool {
|
||||||
fn from_register(a: Register) -> bool {
|
fn from_register(a: Register) -> bool {
|
||||||
if a != 0 { true } else { false }
|
if a != 0 { true } else { false }
|
||||||
@ -121,6 +134,7 @@ impl RegisterArgument for bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[unstable(feature = "sgx_platform", issue = "56975")]
|
||||||
impl<T: RegisterArgument> RegisterArgument for Option<NonNull<T>> {
|
impl<T: RegisterArgument> RegisterArgument for Option<NonNull<T>> {
|
||||||
fn from_register(a: Register) -> Option<NonNull<T>> {
|
fn from_register(a: Register) -> Option<NonNull<T>> {
|
||||||
NonNull::new(a as _)
|
NonNull::new(a as _)
|
||||||
@ -130,12 +144,14 @@ impl<T: RegisterArgument> RegisterArgument for Option<NonNull<T>> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[unstable(feature = "sgx_platform", issue = "56975")]
|
||||||
impl ReturnValue for ! {
|
impl ReturnValue for ! {
|
||||||
fn from_registers(call: &'static str, _regs: (Register, Register)) -> Self {
|
fn from_registers(call: &'static str, _regs: (Register, Register)) -> Self {
|
||||||
rtabort!("Usercall {call}: did not expect to be re-entered");
|
rtabort!("Usercall {call}: did not expect to be re-entered");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[unstable(feature = "sgx_platform", issue = "56975")]
|
||||||
impl ReturnValue for () {
|
impl ReturnValue for () {
|
||||||
fn from_registers(call: &'static str, usercall_retval: (Register, Register)) -> Self {
|
fn from_registers(call: &'static str, usercall_retval: (Register, Register)) -> Self {
|
||||||
rtassert!(usercall_retval.0 == 0);
|
rtassert!(usercall_retval.0 == 0);
|
||||||
@ -144,6 +160,7 @@ impl ReturnValue for () {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[unstable(feature = "sgx_platform", issue = "56975")]
|
||||||
impl<T: RegisterArgument> ReturnValue for T {
|
impl<T: RegisterArgument> ReturnValue for T {
|
||||||
fn from_registers(call: &'static str, usercall_retval: (Register, Register)) -> Self {
|
fn from_registers(call: &'static str, usercall_retval: (Register, Register)) -> Self {
|
||||||
rtassert!(usercall_retval.1 == 0);
|
rtassert!(usercall_retval.1 == 0);
|
||||||
@ -151,6 +168,7 @@ impl<T: RegisterArgument> ReturnValue for T {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[unstable(feature = "sgx_platform", issue = "56975")]
|
||||||
impl<T: RegisterArgument, U: RegisterArgument> ReturnValue for (T, U) {
|
impl<T: RegisterArgument, U: RegisterArgument> ReturnValue for (T, U) {
|
||||||
fn from_registers(_call: &'static str, regs: (Register, Register)) -> Self {
|
fn from_registers(_call: &'static str, regs: (Register, Register)) -> Self {
|
||||||
(T::from_register(regs.0), U::from_register(regs.1))
|
(T::from_register(regs.0), U::from_register(regs.1))
|
||||||
|
@ -11,7 +11,7 @@ use crate::str;
|
|||||||
use crate::sync::Arc;
|
use crate::sync::Arc;
|
||||||
use crate::sys_common::{AsInner, IntoInner};
|
use crate::sys_common::{AsInner, IntoInner};
|
||||||
|
|
||||||
use core::str::lossy::{Utf8Lossy, Utf8LossyChunk};
|
use core::str::Utf8Chunks;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[path = "../unix/os_str/tests.rs"]
|
#[path = "../unix/os_str/tests.rs"]
|
||||||
@ -29,26 +29,32 @@ pub struct Slice {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for Slice {
|
impl fmt::Debug for Slice {
|
||||||
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
// Writes out a valid unicode string with the correct escape sequences
|
fmt::Debug::fmt(&Utf8Chunks::new(&self.inner).debug(), f)
|
||||||
|
|
||||||
formatter.write_str("\"")?;
|
|
||||||
for Utf8LossyChunk { valid, broken } in Utf8Lossy::from_bytes(&self.inner).chunks() {
|
|
||||||
for c in valid.chars().flat_map(|c| c.escape_debug()) {
|
|
||||||
formatter.write_char(c)?
|
|
||||||
}
|
|
||||||
|
|
||||||
for b in broken {
|
|
||||||
write!(formatter, "\\x{:02X}", b)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
formatter.write_str("\"")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for Slice {
|
impl fmt::Display for Slice {
|
||||||
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
fmt::Display::fmt(&Utf8Lossy::from_bytes(&self.inner), formatter)
|
// If we're the empty string then our iterator won't actually yield
|
||||||
|
// anything, so perform the formatting manually
|
||||||
|
if self.inner.is_empty() {
|
||||||
|
return "".fmt(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
for chunk in Utf8Chunks::new(&self.inner) {
|
||||||
|
let valid = chunk.valid();
|
||||||
|
// If we successfully decoded the whole chunk as a valid string then
|
||||||
|
// we can return a direct formatting of the string which will also
|
||||||
|
// respect various formatting flags if possible.
|
||||||
|
if chunk.invalid().is_empty() {
|
||||||
|
return valid.fmt(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
f.write_str(valid)?;
|
||||||
|
f.write_char(char::REPLACEMENT_CHARACTER)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,3 +8,11 @@ fn slice_debug_output() {
|
|||||||
|
|
||||||
assert_eq!(output, expected);
|
assert_eq!(output, expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn display() {
|
||||||
|
assert_eq!(
|
||||||
|
"Hello\u{FFFD}\u{FFFD} There\u{FFFD} Goodbye",
|
||||||
|
Slice::from_u8_slice(b"Hello\xC0\x80 There\xE6\x83 Goodbye").to_string(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
@ -228,6 +228,8 @@ pub const IPV6_ADD_MEMBERSHIP: c_int = 12;
|
|||||||
pub const IPV6_DROP_MEMBERSHIP: c_int = 13;
|
pub const IPV6_DROP_MEMBERSHIP: c_int = 13;
|
||||||
pub const MSG_PEEK: c_int = 0x2;
|
pub const MSG_PEEK: c_int = 0x2;
|
||||||
|
|
||||||
|
pub const LOAD_LIBRARY_SEARCH_SYSTEM32: u32 = 0x800;
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
pub struct linger {
|
pub struct linger {
|
||||||
@ -1030,6 +1032,7 @@ extern "system" {
|
|||||||
pub fn GetProcAddress(handle: HMODULE, name: LPCSTR) -> *mut c_void;
|
pub fn GetProcAddress(handle: HMODULE, name: LPCSTR) -> *mut c_void;
|
||||||
pub fn GetModuleHandleA(lpModuleName: LPCSTR) -> HMODULE;
|
pub fn GetModuleHandleA(lpModuleName: LPCSTR) -> HMODULE;
|
||||||
pub fn GetModuleHandleW(lpModuleName: LPCWSTR) -> HMODULE;
|
pub fn GetModuleHandleW(lpModuleName: LPCWSTR) -> HMODULE;
|
||||||
|
pub fn LoadLibraryExA(lplibfilename: *const i8, hfile: HANDLE, dwflags: u32) -> HINSTANCE;
|
||||||
|
|
||||||
pub fn GetSystemTimeAsFileTime(lpSystemTimeAsFileTime: LPFILETIME);
|
pub fn GetSystemTimeAsFileTime(lpSystemTimeAsFileTime: LPFILETIME);
|
||||||
pub fn GetSystemInfo(lpSystemInfo: LPSYSTEM_INFO);
|
pub fn GetSystemInfo(lpSystemInfo: LPSYSTEM_INFO);
|
||||||
@ -1250,21 +1253,16 @@ compat_fn_with_fallback! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
compat_fn_with_fallback! {
|
compat_fn_optional! {
|
||||||
pub static SYNCH_API: &CStr = ansi_str!("api-ms-win-core-synch-l1-2-0");
|
crate::sys::compat::load_synch_functions();
|
||||||
#[allow(unused)]
|
pub fn WaitOnAddress(
|
||||||
fn WakeByAddressSingle(Address: LPVOID) -> () {
|
Address: LPVOID,
|
||||||
// This fallback is currently tightly coupled to its use in Parker::unpark.
|
CompareAddress: LPVOID,
|
||||||
//
|
AddressSize: SIZE_T,
|
||||||
// FIXME: If `WakeByAddressSingle` needs to be used anywhere other than
|
dwMilliseconds: DWORD
|
||||||
// Parker::unpark then this fallback will be wrong and will need to be decoupled.
|
);
|
||||||
crate::sys::windows::thread_parker::unpark_keyed_event(Address)
|
pub fn WakeByAddressSingle(Address: LPVOID);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
pub use crate::sys::compat::WaitOnAddress;
|
|
||||||
// Change exported name of `WakeByAddressSingle` to make the strange fallback
|
|
||||||
// behaviour clear.
|
|
||||||
pub use WakeByAddressSingle::call as wake_by_address_single_or_unpark_keyed_event;
|
|
||||||
|
|
||||||
compat_fn_with_fallback! {
|
compat_fn_with_fallback! {
|
||||||
pub static NTDLL: &CStr = ansi_str!("ntdll");
|
pub static NTDLL: &CStr = ansi_str!("ntdll");
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
|
|
||||||
use crate::ffi::{c_void, CStr};
|
use crate::ffi::{c_void, CStr};
|
||||||
use crate::ptr::NonNull;
|
use crate::ptr::NonNull;
|
||||||
|
use crate::sync::atomic::{AtomicBool, Ordering};
|
||||||
use crate::sys::c;
|
use crate::sys::c;
|
||||||
|
|
||||||
/// Helper macro for creating CStrs from literals and symbol names.
|
/// Helper macro for creating CStrs from literals and symbol names.
|
||||||
@ -74,6 +75,20 @@ impl Module {
|
|||||||
NonNull::new(module).map(Self)
|
NonNull::new(module).map(Self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Load the library (if not already loaded)
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// The module must not be unloaded.
|
||||||
|
pub unsafe fn load_system_library(name: &CStr) -> Option<Self> {
|
||||||
|
let module = c::LoadLibraryExA(
|
||||||
|
name.as_ptr(),
|
||||||
|
crate::ptr::null_mut(),
|
||||||
|
c::LOAD_LIBRARY_SEARCH_SYSTEM32,
|
||||||
|
);
|
||||||
|
NonNull::new(module).map(Self)
|
||||||
|
}
|
||||||
|
|
||||||
// Try to get the address of a function.
|
// Try to get the address of a function.
|
||||||
pub fn proc_address(self, name: &CStr) -> Option<NonNull<c_void>> {
|
pub fn proc_address(self, name: &CStr) -> Option<NonNull<c_void>> {
|
||||||
// SAFETY:
|
// SAFETY:
|
||||||
@ -144,61 +159,63 @@ macro_rules! compat_fn_with_fallback {
|
|||||||
)*)
|
)*)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Optionally load `WaitOnAddress`.
|
/// Optionally loaded functions.
|
||||||
/// Unlike the dynamic loading described above, this does not have a fallback.
|
|
||||||
///
|
///
|
||||||
/// This is rexported from sys::c. You should prefer to import
|
/// Actual loading of the function defers to $load_functions.
|
||||||
/// from there in case this changes again in the future.
|
macro_rules! compat_fn_optional {
|
||||||
pub mod WaitOnAddress {
|
($load_functions:expr;
|
||||||
use super::*;
|
$(
|
||||||
use crate::mem;
|
$(#[$meta:meta])*
|
||||||
use crate::ptr;
|
$vis:vis fn $symbol:ident($($argname:ident: $argtype:ty),*) $(-> $rettype:ty)?;
|
||||||
use crate::sync::atomic::{AtomicBool, AtomicPtr, Ordering};
|
)+) => (
|
||||||
use crate::sys::c;
|
$(
|
||||||
|
pub mod $symbol {
|
||||||
|
use super::*;
|
||||||
|
use crate::ffi::c_void;
|
||||||
|
use crate::mem;
|
||||||
|
use crate::ptr::{self, NonNull};
|
||||||
|
use crate::sync::atomic::{AtomicPtr, Ordering};
|
||||||
|
|
||||||
static MODULE_NAME: &CStr = ansi_str!("api-ms-win-core-synch-l1-2-0");
|
pub(in crate::sys) static PTR: AtomicPtr<c_void> = AtomicPtr::new(ptr::null_mut());
|
||||||
static SYMBOL_NAME: &CStr = ansi_str!("WaitOnAddress");
|
|
||||||
|
|
||||||
// WaitOnAddress function signature.
|
type F = unsafe extern "system" fn($($argtype),*) $(-> $rettype)?;
|
||||||
type F = unsafe extern "system" fn(
|
|
||||||
Address: c::LPVOID,
|
|
||||||
CompareAddress: c::LPVOID,
|
|
||||||
AddressSize: c::SIZE_T,
|
|
||||||
dwMilliseconds: c::DWORD,
|
|
||||||
);
|
|
||||||
|
|
||||||
// A place to store the loaded function atomically.
|
#[inline(always)]
|
||||||
static WAIT_ON_ADDRESS: AtomicPtr<c_void> = AtomicPtr::new(ptr::null_mut());
|
pub fn option() -> Option<F> {
|
||||||
|
let f = PTR.load(Ordering::Acquire);
|
||||||
|
if !f.is_null() { Some(unsafe { mem::transmute(f) }) } else { try_load() }
|
||||||
|
}
|
||||||
|
|
||||||
// We can skip trying to load again if we already tried.
|
#[cold]
|
||||||
static LOAD_MODULE: AtomicBool = AtomicBool::new(true);
|
fn try_load() -> Option<F> {
|
||||||
|
$load_functions;
|
||||||
#[inline(always)]
|
NonNull::new(PTR.load(Ordering::Acquire)).map(|f| unsafe { mem::transmute(f) })
|
||||||
pub fn option() -> Option<F> {
|
}
|
||||||
let f = WAIT_ON_ADDRESS.load(Ordering::Acquire);
|
|
||||||
if !f.is_null() { Some(unsafe { mem::transmute(f) }) } else { try_load() }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cold]
|
|
||||||
fn try_load() -> Option<F> {
|
|
||||||
if LOAD_MODULE.load(Ordering::Acquire) {
|
|
||||||
// load the module
|
|
||||||
let mut wait_on_address = None;
|
|
||||||
if let Some(func) = try_load_inner() {
|
|
||||||
WAIT_ON_ADDRESS.store(func.as_ptr(), Ordering::Release);
|
|
||||||
wait_on_address = Some(unsafe { mem::transmute(func) });
|
|
||||||
}
|
}
|
||||||
// Don't try to load the module again even if loading failed.
|
)+
|
||||||
LOAD_MODULE.store(false, Ordering::Release);
|
)
|
||||||
wait_on_address
|
}
|
||||||
} else {
|
|
||||||
None
|
/// Load all needed functions from "api-ms-win-core-synch-l1-2-0".
|
||||||
}
|
pub(super) fn load_synch_functions() {
|
||||||
|
fn try_load() -> Option<()> {
|
||||||
|
const MODULE_NAME: &CStr = ansi_str!("api-ms-win-core-synch-l1-2-0");
|
||||||
|
const WAIT_ON_ADDRESS: &CStr = ansi_str!("WaitOnAddress");
|
||||||
|
const WAKE_BY_ADDRESS_SINGLE: &CStr = ansi_str!("WakeByAddressSingle");
|
||||||
|
|
||||||
|
// Try loading the library and all the required functions.
|
||||||
|
// If any step fails, then they all fail.
|
||||||
|
let library = unsafe { Module::load_system_library(MODULE_NAME) }?;
|
||||||
|
let wait_on_address = library.proc_address(WAIT_ON_ADDRESS)?;
|
||||||
|
let wake_by_address_single = library.proc_address(WAKE_BY_ADDRESS_SINGLE)?;
|
||||||
|
|
||||||
|
c::WaitOnAddress::PTR.store(wait_on_address.as_ptr(), Ordering::Release);
|
||||||
|
c::WakeByAddressSingle::PTR.store(wake_by_address_single.as_ptr(), Ordering::Release);
|
||||||
|
Some(())
|
||||||
}
|
}
|
||||||
|
|
||||||
// In the future this could be a `try` block but until then I think it's a
|
// Try to load the module but skip loading if a previous attempt failed.
|
||||||
// little bit cleaner as a separate function.
|
static LOAD_MODULE: AtomicBool = AtomicBool::new(true);
|
||||||
fn try_load_inner() -> Option<NonNull<c_void>> {
|
let module_loaded = LOAD_MODULE.load(Ordering::Acquire) && try_load().is_some();
|
||||||
unsafe { Module::new(MODULE_NAME)?.proc_address(SYMBOL_NAME) }
|
LOAD_MODULE.store(module_loaded, Ordering::Release)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -198,8 +198,18 @@ impl Parker {
|
|||||||
// with park().
|
// with park().
|
||||||
if self.state.swap(NOTIFIED, Release) == PARKED {
|
if self.state.swap(NOTIFIED, Release) == PARKED {
|
||||||
unsafe {
|
unsafe {
|
||||||
// This calls either WakeByAddressSingle or unpark_keyed_event (see below).
|
if let Some(wake_by_address_single) = c::WakeByAddressSingle::option() {
|
||||||
c::wake_by_address_single_or_unpark_keyed_event(self.ptr());
|
wake_by_address_single(self.ptr());
|
||||||
|
} else {
|
||||||
|
// If we run NtReleaseKeyedEvent before the waiting thread runs
|
||||||
|
// NtWaitForKeyedEvent, this (shortly) blocks until we can wake it up.
|
||||||
|
// If the waiting thread wakes up before we run NtReleaseKeyedEvent
|
||||||
|
// (e.g. due to a timeout), this blocks until we do wake up a thread.
|
||||||
|
// To prevent this thread from blocking indefinitely in that case,
|
||||||
|
// park_impl() will, after seeing the state set to NOTIFIED after
|
||||||
|
// waking up, call NtWaitForKeyedEvent again to unblock us.
|
||||||
|
c::NtReleaseKeyedEvent(keyed_event_handle(), self.ptr(), 0, ptr::null_mut());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -209,19 +219,6 @@ impl Parker {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// This function signature makes it compatible with c::WakeByAddressSingle
|
|
||||||
// so that it can be used as a fallback for that function.
|
|
||||||
pub unsafe extern "C" fn unpark_keyed_event(address: c::LPVOID) {
|
|
||||||
// If we run NtReleaseKeyedEvent before the waiting thread runs
|
|
||||||
// NtWaitForKeyedEvent, this (shortly) blocks until we can wake it up.
|
|
||||||
// If the waiting thread wakes up before we run NtReleaseKeyedEvent
|
|
||||||
// (e.g. due to a timeout), this blocks until we do wake up a thread.
|
|
||||||
// To prevent this thread from blocking indefinitely in that case,
|
|
||||||
// park_impl() will, after seeing the state set to NOTIFIED after
|
|
||||||
// waking up, call NtWaitForKeyedEvent again to unblock us.
|
|
||||||
c::NtReleaseKeyedEvent(keyed_event_handle(), address, 0, ptr::null_mut());
|
|
||||||
}
|
|
||||||
|
|
||||||
fn keyed_event_handle() -> c::HANDLE {
|
fn keyed_event_handle() -> c::HANDLE {
|
||||||
const INVALID: c::HANDLE = ptr::invalid_mut(!0);
|
const INVALID: c::HANDLE = ptr::invalid_mut(!0);
|
||||||
static HANDLE: AtomicPtr<libc::c_void> = AtomicPtr::new(INVALID);
|
static HANDLE: AtomicPtr<libc::c_void> = AtomicPtr::new(INVALID);
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
FROM ubuntu:18.04
|
FROM ubuntu:18.04
|
||||||
|
# FIXME: when bumping the version, remove the Python 3.6-specific changes in
|
||||||
|
# the reuse-requirements.in file, regenerate reuse-requirements.txt and remove
|
||||||
|
# this comment.
|
||||||
|
|
||||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||||
g++ \
|
g++ \
|
||||||
@ -8,6 +11,8 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
|||||||
curl \
|
curl \
|
||||||
ca-certificates \
|
ca-certificates \
|
||||||
python3 \
|
python3 \
|
||||||
|
python3-pip \
|
||||||
|
python3-pkg-resources \
|
||||||
git \
|
git \
|
||||||
cmake \
|
cmake \
|
||||||
sudo \
|
sudo \
|
||||||
@ -27,6 +32,9 @@ RUN npm install eslint@8.6.0 -g
|
|||||||
COPY scripts/sccache.sh /scripts/
|
COPY scripts/sccache.sh /scripts/
|
||||||
RUN sh /scripts/sccache.sh
|
RUN sh /scripts/sccache.sh
|
||||||
|
|
||||||
|
COPY host-x86_64/mingw-check/reuse-requirements.txt /tmp/
|
||||||
|
RUN pip3 install --no-deps --require-hashes -r /tmp/reuse-requirements.txt
|
||||||
|
|
||||||
COPY host-x86_64/mingw-check/validate-toolstate.sh /scripts/
|
COPY host-x86_64/mingw-check/validate-toolstate.sh /scripts/
|
||||||
COPY host-x86_64/mingw-check/validate-error-codes.sh /scripts/
|
COPY host-x86_64/mingw-check/validate-error-codes.sh /scripts/
|
||||||
|
|
||||||
@ -40,6 +48,7 @@ ENV SCRIPT python3 ../x.py --stage 2 test src/tools/expand-yaml-anchors && \
|
|||||||
python3 ../x.py doc --stage 0 library/test && \
|
python3 ../x.py doc --stage 0 library/test && \
|
||||||
/scripts/validate-toolstate.sh && \
|
/scripts/validate-toolstate.sh && \
|
||||||
/scripts/validate-error-codes.sh && \
|
/scripts/validate-error-codes.sh && \
|
||||||
|
reuse lint && \
|
||||||
# Runs checks to ensure that there are no ES5 issues in our JS code.
|
# Runs checks to ensure that there are no ES5 issues in our JS code.
|
||||||
es-check es6 ../src/librustdoc/html/static/js/*.js && \
|
es-check es6 ../src/librustdoc/html/static/js/*.js && \
|
||||||
eslint -c ../src/librustdoc/html/static/.eslintrc.js ../src/librustdoc/html/static/js/*.js
|
eslint -c ../src/librustdoc/html/static/.eslintrc.js ../src/librustdoc/html/static/js/*.js
|
||||||
|
22
src/ci/docker/host-x86_64/mingw-check/reuse-requirements.in
Normal file
22
src/ci/docker/host-x86_64/mingw-check/reuse-requirements.in
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
# This is the template for reuse-requirements.txt.
|
||||||
|
#
|
||||||
|
# The pip-tools project is used to generate the file again. To install it, the
|
||||||
|
# recommended way is to:
|
||||||
|
#
|
||||||
|
# - Install pipx from https://github.com/pypa/pipx
|
||||||
|
# - Run `pipx install pip-tools`
|
||||||
|
#
|
||||||
|
# Once pip-tools is installed, run this command to regenerate the .txt file:
|
||||||
|
#
|
||||||
|
# pip-compile --allow-unsafe --generate-hashes reuse-requirements.in
|
||||||
|
#
|
||||||
|
|
||||||
|
reuse
|
||||||
|
|
||||||
|
# Some packages dropped support for Python 3.6, which is the version used in
|
||||||
|
# this builder (due to Ubuntu 18.04). This should be removed once we bump the
|
||||||
|
# Ubuntu version of the builder.
|
||||||
|
jinja2 < 3.1
|
||||||
|
markupsafe < 2.1
|
||||||
|
requests < 2.28
|
||||||
|
setuptools < 59.7
|
145
src/ci/docker/host-x86_64/mingw-check/reuse-requirements.txt
Normal file
145
src/ci/docker/host-x86_64/mingw-check/reuse-requirements.txt
Normal file
@ -0,0 +1,145 @@
|
|||||||
|
#
|
||||||
|
# This file is autogenerated by pip-compile with python 3.10
|
||||||
|
# To update, run:
|
||||||
|
#
|
||||||
|
# pip-compile --allow-unsafe --generate-hashes reuse-requirements.in
|
||||||
|
#
|
||||||
|
binaryornot==0.4.4 \
|
||||||
|
--hash=sha256:359501dfc9d40632edc9fac890e19542db1a287bbcfa58175b66658392018061 \
|
||||||
|
--hash=sha256:b8b71173c917bddcd2c16070412e369c3ed7f0528926f70cac18a6c97fd563e4
|
||||||
|
# via reuse
|
||||||
|
boolean-py==3.8 \
|
||||||
|
--hash=sha256:cc24e20f985d60cd4a3a5a1c0956dd12611159d32a75081dabd0c9ab981acaa4 \
|
||||||
|
--hash=sha256:d75da0fd0354425fa64f6bbc6cec6ae1485d0eec3447b73187ff8cbf9b572e26
|
||||||
|
# via
|
||||||
|
# license-expression
|
||||||
|
# reuse
|
||||||
|
certifi==2022.6.15 \
|
||||||
|
--hash=sha256:84c85a9078b11105f04f3036a9482ae10e4621616db313fe045dd24743a0820d \
|
||||||
|
--hash=sha256:fe86415d55e84719d75f8b69414f6438ac3547d2078ab91b67e779ef69378412
|
||||||
|
# via requests
|
||||||
|
chardet==5.0.0 \
|
||||||
|
--hash=sha256:0368df2bfd78b5fc20572bb4e9bb7fb53e2c094f60ae9993339e8671d0afb8aa \
|
||||||
|
--hash=sha256:d3e64f022d254183001eccc5db4040520c0f23b1a3f33d6413e099eb7f126557
|
||||||
|
# via
|
||||||
|
# binaryornot
|
||||||
|
# python-debian
|
||||||
|
charset-normalizer==2.0.12 \
|
||||||
|
--hash=sha256:2857e29ff0d34db842cd7ca3230549d1a697f96ee6d3fb071cfa6c7393832597 \
|
||||||
|
--hash=sha256:6881edbebdb17b39b4eaaa821b438bf6eddffb4468cf344f09f89def34a8b1df
|
||||||
|
# via requests
|
||||||
|
idna==3.3 \
|
||||||
|
--hash=sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff \
|
||||||
|
--hash=sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d
|
||||||
|
# via requests
|
||||||
|
jinja2==3.0.3 \
|
||||||
|
--hash=sha256:077ce6014f7b40d03b47d1f1ca4b0fc8328a692bd284016f806ed0eaca390ad8 \
|
||||||
|
--hash=sha256:611bb273cd68f3b993fabdc4064fc858c5b47a973cb5aa7999ec1ba405c87cd7
|
||||||
|
# via
|
||||||
|
# -r reuse-requirements.in
|
||||||
|
# reuse
|
||||||
|
license-expression==21.6.14 \
|
||||||
|
--hash=sha256:324246eed8e138b4139fefdc0e9dc4161d5075e3929e56983966d37298dca30e \
|
||||||
|
--hash=sha256:9de87a427c9a449eee7913472fb9ed03b63036295547369fdbf95f76a8b924b2
|
||||||
|
# via
|
||||||
|
# -r reuse-requirements.in
|
||||||
|
# reuse
|
||||||
|
markupsafe==2.0.1 \
|
||||||
|
--hash=sha256:01a9b8ea66f1658938f65b93a85ebe8bc016e6769611be228d797c9d998dd298 \
|
||||||
|
--hash=sha256:023cb26ec21ece8dc3907c0e8320058b2e0cb3c55cf9564da612bc325bed5e64 \
|
||||||
|
--hash=sha256:0446679737af14f45767963a1a9ef7620189912317d095f2d9ffa183a4d25d2b \
|
||||||
|
--hash=sha256:04635854b943835a6ea959e948d19dcd311762c5c0c6e1f0e16ee57022669194 \
|
||||||
|
--hash=sha256:0717a7390a68be14b8c793ba258e075c6f4ca819f15edfc2a3a027c823718567 \
|
||||||
|
--hash=sha256:0955295dd5eec6cb6cc2fe1698f4c6d84af2e92de33fbcac4111913cd100a6ff \
|
||||||
|
--hash=sha256:0d4b31cc67ab36e3392bbf3862cfbadac3db12bdd8b02a2731f509ed5b829724 \
|
||||||
|
--hash=sha256:10f82115e21dc0dfec9ab5c0223652f7197feb168c940f3ef61563fc2d6beb74 \
|
||||||
|
--hash=sha256:168cd0a3642de83558a5153c8bd34f175a9a6e7f6dc6384b9655d2697312a646 \
|
||||||
|
--hash=sha256:1d609f577dc6e1aa17d746f8bd3c31aa4d258f4070d61b2aa5c4166c1539de35 \
|
||||||
|
--hash=sha256:1f2ade76b9903f39aa442b4aadd2177decb66525062db244b35d71d0ee8599b6 \
|
||||||
|
--hash=sha256:20dca64a3ef2d6e4d5d615a3fd418ad3bde77a47ec8a23d984a12b5b4c74491a \
|
||||||
|
--hash=sha256:2a7d351cbd8cfeb19ca00de495e224dea7e7d919659c2841bbb7f420ad03e2d6 \
|
||||||
|
--hash=sha256:2d7d807855b419fc2ed3e631034685db6079889a1f01d5d9dac950f764da3dad \
|
||||||
|
--hash=sha256:2ef54abee730b502252bcdf31b10dacb0a416229b72c18b19e24a4509f273d26 \
|
||||||
|
--hash=sha256:36bc903cbb393720fad60fc28c10de6acf10dc6cc883f3e24ee4012371399a38 \
|
||||||
|
--hash=sha256:37205cac2a79194e3750b0af2a5720d95f786a55ce7df90c3af697bfa100eaac \
|
||||||
|
--hash=sha256:3c112550557578c26af18a1ccc9e090bfe03832ae994343cfdacd287db6a6ae7 \
|
||||||
|
--hash=sha256:3dd007d54ee88b46be476e293f48c85048603f5f516008bee124ddd891398ed6 \
|
||||||
|
--hash=sha256:4296f2b1ce8c86a6aea78613c34bb1a672ea0e3de9c6ba08a960efe0b0a09047 \
|
||||||
|
--hash=sha256:47ab1e7b91c098ab893b828deafa1203de86d0bc6ab587b160f78fe6c4011f75 \
|
||||||
|
--hash=sha256:49e3ceeabbfb9d66c3aef5af3a60cc43b85c33df25ce03d0031a608b0a8b2e3f \
|
||||||
|
--hash=sha256:4dc8f9fb58f7364b63fd9f85013b780ef83c11857ae79f2feda41e270468dd9b \
|
||||||
|
--hash=sha256:4efca8f86c54b22348a5467704e3fec767b2db12fc39c6d963168ab1d3fc9135 \
|
||||||
|
--hash=sha256:53edb4da6925ad13c07b6d26c2a852bd81e364f95301c66e930ab2aef5b5ddd8 \
|
||||||
|
--hash=sha256:5855f8438a7d1d458206a2466bf82b0f104a3724bf96a1c781ab731e4201731a \
|
||||||
|
--hash=sha256:594c67807fb16238b30c44bdf74f36c02cdf22d1c8cda91ef8a0ed8dabf5620a \
|
||||||
|
--hash=sha256:5b6d930f030f8ed98e3e6c98ffa0652bdb82601e7a016ec2ab5d7ff23baa78d1 \
|
||||||
|
--hash=sha256:5bb28c636d87e840583ee3adeb78172efc47c8b26127267f54a9c0ec251d41a9 \
|
||||||
|
--hash=sha256:60bf42e36abfaf9aff1f50f52644b336d4f0a3fd6d8a60ca0d054ac9f713a864 \
|
||||||
|
--hash=sha256:611d1ad9a4288cf3e3c16014564df047fe08410e628f89805e475368bd304914 \
|
||||||
|
--hash=sha256:6300b8454aa6930a24b9618fbb54b5a68135092bc666f7b06901f897fa5c2fee \
|
||||||
|
--hash=sha256:63f3268ba69ace99cab4e3e3b5840b03340efed0948ab8f78d2fd87ee5442a4f \
|
||||||
|
--hash=sha256:6557b31b5e2c9ddf0de32a691f2312a32f77cd7681d8af66c2692efdbef84c18 \
|
||||||
|
--hash=sha256:693ce3f9e70a6cf7d2fb9e6c9d8b204b6b39897a2c4a1aa65728d5ac97dcc1d8 \
|
||||||
|
--hash=sha256:6a7fae0dd14cf60ad5ff42baa2e95727c3d81ded453457771d02b7d2b3f9c0c2 \
|
||||||
|
--hash=sha256:6c4ca60fa24e85fe25b912b01e62cb969d69a23a5d5867682dd3e80b5b02581d \
|
||||||
|
--hash=sha256:6fcf051089389abe060c9cd7caa212c707e58153afa2c649f00346ce6d260f1b \
|
||||||
|
--hash=sha256:7d91275b0245b1da4d4cfa07e0faedd5b0812efc15b702576d103293e252af1b \
|
||||||
|
--hash=sha256:89c687013cb1cd489a0f0ac24febe8c7a666e6e221b783e53ac50ebf68e45d86 \
|
||||||
|
--hash=sha256:8d206346619592c6200148b01a2142798c989edcb9c896f9ac9722a99d4e77e6 \
|
||||||
|
--hash=sha256:905fec760bd2fa1388bb5b489ee8ee5f7291d692638ea5f67982d968366bef9f \
|
||||||
|
--hash=sha256:97383d78eb34da7e1fa37dd273c20ad4320929af65d156e35a5e2d89566d9dfb \
|
||||||
|
--hash=sha256:984d76483eb32f1bcb536dc27e4ad56bba4baa70be32fa87152832cdd9db0833 \
|
||||||
|
--hash=sha256:99df47edb6bda1249d3e80fdabb1dab8c08ef3975f69aed437cb69d0a5de1e28 \
|
||||||
|
--hash=sha256:9f02365d4e99430a12647f09b6cc8bab61a6564363f313126f775eb4f6ef798e \
|
||||||
|
--hash=sha256:a30e67a65b53ea0a5e62fe23682cfe22712e01f453b95233b25502f7c61cb415 \
|
||||||
|
--hash=sha256:ab3ef638ace319fa26553db0624c4699e31a28bb2a835c5faca8f8acf6a5a902 \
|
||||||
|
--hash=sha256:aca6377c0cb8a8253e493c6b451565ac77e98c2951c45f913e0b52facdcff83f \
|
||||||
|
--hash=sha256:add36cb2dbb8b736611303cd3bfcee00afd96471b09cda130da3581cbdc56a6d \
|
||||||
|
--hash=sha256:b2f4bf27480f5e5e8ce285a8c8fd176c0b03e93dcc6646477d4630e83440c6a9 \
|
||||||
|
--hash=sha256:b7f2d075102dc8c794cbde1947378051c4e5180d52d276987b8d28a3bd58c17d \
|
||||||
|
--hash=sha256:baa1a4e8f868845af802979fcdbf0bb11f94f1cb7ced4c4b8a351bb60d108145 \
|
||||||
|
--hash=sha256:be98f628055368795d818ebf93da628541e10b75b41c559fdf36d104c5787066 \
|
||||||
|
--hash=sha256:bf5d821ffabf0ef3533c39c518f3357b171a1651c1ff6827325e4489b0e46c3c \
|
||||||
|
--hash=sha256:c47adbc92fc1bb2b3274c4b3a43ae0e4573d9fbff4f54cd484555edbf030baf1 \
|
||||||
|
--hash=sha256:cdfba22ea2f0029c9261a4bd07e830a8da012291fbe44dc794e488b6c9bb353a \
|
||||||
|
--hash=sha256:d6c7ebd4e944c85e2c3421e612a7057a2f48d478d79e61800d81468a8d842207 \
|
||||||
|
--hash=sha256:d7f9850398e85aba693bb640262d3611788b1f29a79f0c93c565694658f4071f \
|
||||||
|
--hash=sha256:d8446c54dc28c01e5a2dbac5a25f071f6653e6e40f3a8818e8b45d790fe6ef53 \
|
||||||
|
--hash=sha256:deb993cacb280823246a026e3b2d81c493c53de6acfd5e6bfe31ab3402bb37dd \
|
||||||
|
--hash=sha256:e0f138900af21926a02425cf736db95be9f4af72ba1bb21453432a07f6082134 \
|
||||||
|
--hash=sha256:e9936f0b261d4df76ad22f8fee3ae83b60d7c3e871292cd42f40b81b70afae85 \
|
||||||
|
--hash=sha256:f0567c4dc99f264f49fe27da5f735f414c4e7e7dd850cfd8e69f0862d7c74ea9 \
|
||||||
|
--hash=sha256:f5653a225f31e113b152e56f154ccbe59eeb1c7487b39b9d9f9cdb58e6c79dc5 \
|
||||||
|
--hash=sha256:f826e31d18b516f653fe296d967d700fddad5901ae07c622bb3705955e1faa94 \
|
||||||
|
--hash=sha256:f8ba0e8349a38d3001fae7eadded3f6606f0da5d748ee53cc1dab1d6527b9509 \
|
||||||
|
--hash=sha256:f9081981fe268bd86831e5c75f7de206ef275defcb82bc70740ae6dc507aee51 \
|
||||||
|
--hash=sha256:fa130dd50c57d53368c9d59395cb5526eda596d3ffe36666cd81a44d56e48872
|
||||||
|
# via
|
||||||
|
# -r reuse-requirements.in
|
||||||
|
# jinja2
|
||||||
|
python-debian==0.1.44 \
|
||||||
|
--hash=sha256:11bd6f01c46da57982bdd66dd595e2d240feb32a85de3fd37c452102fd0337ab \
|
||||||
|
--hash=sha256:65592fe3b64f6c6c93d94e2d2599db5e0c22831d3bcff07cb7b96d3840b1333e
|
||||||
|
# via reuse
|
||||||
|
requests==2.26.0 \
|
||||||
|
--hash=sha256:6c1246513ecd5ecd4528a0906f910e8f0f9c6b8ec72030dc9fd154dc1a6efd24 \
|
||||||
|
--hash=sha256:b8aa58f8cf793ffd8782d3d8cb19e66ef36f7aba4353eec859e74678b01b07a7
|
||||||
|
# via
|
||||||
|
# -r reuse-requirements.in
|
||||||
|
# reuse
|
||||||
|
reuse==1.0.0 \
|
||||||
|
--hash=sha256:db3022be2d87f69c8f508b928023de3026f454ce17d01e22f770f7147ac1e8d4 \
|
||||||
|
--hash=sha256:e2605e796311c424465d741ea2a1e1ad03bbb90b921d74750119c331ca5af46e
|
||||||
|
# via -r reuse-requirements.in
|
||||||
|
urllib3==1.26.10 \
|
||||||
|
--hash=sha256:8298d6d56d39be0e3bc13c1c97d133f9b45d797169a0e11cdd0e0489d786f7ec \
|
||||||
|
--hash=sha256:879ba4d1e89654d9769ce13121e0f94310ea32e8d2f8cf587b77c08bbcdb30d6
|
||||||
|
# via requests
|
||||||
|
|
||||||
|
# The following packages are considered to be unsafe in a requirements file:
|
||||||
|
setuptools==59.6.0 \
|
||||||
|
--hash=sha256:22c7348c6d2976a52632c67f7ab0cdf40147db7789f9aed18734643fe9cf3373 \
|
||||||
|
--hash=sha256:4ce92f1e1f8f01233ee9952c04f6b81d1e02939d6e1b488428154974a4d0783e
|
||||||
|
# via
|
||||||
|
# -r reuse-requirements.in
|
||||||
|
# reuse
|
54
src/test/codegen/try_question_mark_nop.rs
Normal file
54
src/test/codegen/try_question_mark_nop.rs
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
// min-llvm-version: 15.0
|
||||||
|
// compile-flags: -O -Z merge-functions=disabled --edition=2021
|
||||||
|
// only-x86_64
|
||||||
|
|
||||||
|
#![crate_type = "lib"]
|
||||||
|
#![feature(try_blocks)]
|
||||||
|
|
||||||
|
// These are now NOPs in LLVM 15, presumably thanks to nikic's change mentioned in
|
||||||
|
// <https://github.com/rust-lang/rust/issues/85133#issuecomment-1072168354>.
|
||||||
|
// Unfortunately, as of 2022-08-17 they're not yet nops for `u64`s nor `Option`.
|
||||||
|
|
||||||
|
use std::ops::ControlFlow::{self, Continue, Break};
|
||||||
|
|
||||||
|
// CHECK-LABEL: @result_nop_match_32
|
||||||
|
#[no_mangle]
|
||||||
|
pub fn result_nop_match_32(x: Result<i32, u32>) -> Result<i32, u32> {
|
||||||
|
// CHECK: start
|
||||||
|
// CHECK-NEXT: ret i64 %0
|
||||||
|
match x {
|
||||||
|
Ok(x) => Ok(x),
|
||||||
|
Err(x) => Err(x),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK-LABEL: @result_nop_traits_32
|
||||||
|
#[no_mangle]
|
||||||
|
pub fn result_nop_traits_32(x: Result<i32, u32>) -> Result<i32, u32> {
|
||||||
|
// CHECK: start
|
||||||
|
// CHECK-NEXT: ret i64 %0
|
||||||
|
try {
|
||||||
|
x?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK-LABEL: @control_flow_nop_match_32
|
||||||
|
#[no_mangle]
|
||||||
|
pub fn control_flow_nop_match_32(x: ControlFlow<i32, u32>) -> ControlFlow<i32, u32> {
|
||||||
|
// CHECK: start
|
||||||
|
// CHECK-NEXT: ret i64 %0
|
||||||
|
match x {
|
||||||
|
Continue(x) => Continue(x),
|
||||||
|
Break(x) => Break(x),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK-LABEL: @control_flow_nop_traits_32
|
||||||
|
#[no_mangle]
|
||||||
|
pub fn control_flow_nop_traits_32(x: ControlFlow<i32, u32>) -> ControlFlow<i32, u32> {
|
||||||
|
// CHECK: start
|
||||||
|
// CHECK-NEXT: ret i64 %0
|
||||||
|
try {
|
||||||
|
x?
|
||||||
|
}
|
||||||
|
}
|
@ -1,17 +0,0 @@
|
|||||||
error[E0308]: mismatched types
|
|
||||||
--> $DIR/higher-ranked-projection.rs:25:5
|
|
||||||
|
|
|
||||||
LL | foo(());
|
|
||||||
| ^^^^^^^ one type is more general than the other
|
|
||||||
|
|
|
||||||
= note: expected reference `&'a ()`
|
|
||||||
found reference `&()`
|
|
||||||
note: the lifetime requirement is introduced here
|
|
||||||
--> $DIR/higher-ranked-projection.rs:16:33
|
|
||||||
|
|
|
||||||
LL | where for<'a> &'a T: Mirror<Image=U>
|
|
||||||
| ^^^^^^^
|
|
||||||
|
|
||||||
error: aborting due to previous error
|
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0308`.
|
|
@ -1,2 +0,0 @@
|
|||||||
error: unknown debugging option: `borrowck`
|
|
||||||
|
|
45
src/test/ui/implied-bounds/issue-100690.rs
Normal file
45
src/test/ui/implied-bounds/issue-100690.rs
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
// This code (probably) _should_ compile, but it currently does not because we
|
||||||
|
// are not smart enough about implied bounds.
|
||||||
|
|
||||||
|
use std::io;
|
||||||
|
|
||||||
|
fn real_dispatch<T, F>(f: F) -> Result<(), io::Error>
|
||||||
|
//~^ NOTE required by a bound in this
|
||||||
|
where
|
||||||
|
F: FnOnce(&mut UIView<T>) -> Result<(), io::Error> + Send + 'static,
|
||||||
|
//~^ NOTE required by this bound in `real_dispatch`
|
||||||
|
//~| NOTE required by a bound in `real_dispatch`
|
||||||
|
{
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct UIView<'a, T: 'a> {
|
||||||
|
_phantom: std::marker::PhantomData<&'a mut T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
trait Handle<'a, T: 'a, V, R> {
|
||||||
|
fn dispatch<F>(&self, f: F) -> Result<(), io::Error>
|
||||||
|
where
|
||||||
|
F: FnOnce(&mut V) -> R + Send + 'static;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
struct TUIHandle<T> {
|
||||||
|
_phantom: std::marker::PhantomData<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T: 'a> Handle<'a, T, UIView<'a, T>, Result<(), io::Error>> for TUIHandle<T> {
|
||||||
|
fn dispatch<F>(&self, f: F) -> Result<(), io::Error>
|
||||||
|
where
|
||||||
|
F: FnOnce(&mut UIView<'a, T>) -> Result<(), io::Error> + Send + 'static,
|
||||||
|
{
|
||||||
|
real_dispatch(f)
|
||||||
|
//~^ ERROR expected a `FnOnce<(&mut UIView<'_, T>,)>` closure, found `F`
|
||||||
|
//~| NOTE expected an `FnOnce<(&mut UIView<'_, T>,)>` closure, found `F`
|
||||||
|
//~| NOTE expected a closure with arguments
|
||||||
|
//~| NOTE required by a bound introduced by this call
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
22
src/test/ui/implied-bounds/issue-100690.stderr
Normal file
22
src/test/ui/implied-bounds/issue-100690.stderr
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
error[E0277]: expected a `FnOnce<(&mut UIView<'_, T>,)>` closure, found `F`
|
||||||
|
--> $DIR/issue-100690.rs:37:23
|
||||||
|
|
|
||||||
|
LL | real_dispatch(f)
|
||||||
|
| ------------- ^ expected an `FnOnce<(&mut UIView<'_, T>,)>` closure, found `F`
|
||||||
|
| |
|
||||||
|
| required by a bound introduced by this call
|
||||||
|
|
|
||||||
|
= note: expected a closure with arguments `(&mut UIView<'a, T>,)`
|
||||||
|
found a closure with arguments `(&mut UIView<'_, T>,)`
|
||||||
|
note: required by a bound in `real_dispatch`
|
||||||
|
--> $DIR/issue-100690.rs:9:8
|
||||||
|
|
|
||||||
|
LL | fn real_dispatch<T, F>(f: F) -> Result<(), io::Error>
|
||||||
|
| ------------- required by a bound in this
|
||||||
|
...
|
||||||
|
LL | F: FnOnce(&mut UIView<T>) -> Result<(), io::Error> + Send + 'static,
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `real_dispatch`
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0277`.
|
@ -1,2 +0,0 @@
|
|||||||
error: unknown debugging option: `borrowck`
|
|
||||||
|
|
@ -1,2 +0,0 @@
|
|||||||
error: unknown debugging option: `borrowck`
|
|
||||||
|
|
@ -362,12 +362,12 @@ cc = ["@oli-obk", "@RalfJung", "@JakobDegen", "@davidtwco", "@celinval", "@vakar
|
|||||||
|
|
||||||
[mentions."compiler/rustc_error_messages"]
|
[mentions."compiler/rustc_error_messages"]
|
||||||
message = "`rustc_error_messages` was changed"
|
message = "`rustc_error_messages` was changed"
|
||||||
cc = ["@davidtwco", "@compiler-errors", "@JohnTitor", "@estebank"]
|
cc = ["@davidtwco", "@compiler-errors", "@JohnTitor", "@estebank", "@TaKO8Ki"]
|
||||||
|
|
||||||
[mentions."compiler/rustc_errors/src/translation.rs"]
|
[mentions."compiler/rustc_errors/src/translation.rs"]
|
||||||
message = "`rustc_errors::translation` was changed"
|
message = "`rustc_errors::translation` was changed"
|
||||||
cc = ["@davidtwco", "@compiler-errors", "@JohnTitor", "@estebank"]
|
cc = ["@davidtwco", "@compiler-errors", "@JohnTitor", "@estebank", "@TaKO8Ki"]
|
||||||
|
|
||||||
[mentions."compiler/rustc_macros/src/diagnostics"]
|
[mentions."compiler/rustc_macros/src/diagnostics"]
|
||||||
message = "`rustc_macros::diagnostics` was changed"
|
message = "`rustc_macros::diagnostics` was changed"
|
||||||
cc = ["@davidtwco", "@compiler-errors", "@JohnTitor", "@estebank"]
|
cc = ["@davidtwco", "@compiler-errors", "@JohnTitor", "@estebank", "@TaKO8Ki"]
|
||||||
|
Loading…
Reference in New Issue
Block a user