Auto merge of #68933 - Dylan-DPC:rollup-akz13kj, r=Dylan-DPC

Rollup of 7 pull requests

Successful merges:

 - #68164 (Selectively disable sanitizer instrumentation)
 - #68413 (Add GitHub issue templates)
 - #68889 (Move the `hir().krate()` method to a query and remove the `Krate` dep node)
 - #68909 (Respect --nocapture in panic=abort test mode)
 - #68910 (Add myself to .mailmap)
 - #68919 (Remove HashStable impl for ast::Lifetime)
 - #68928 (clean up E0276 explanation)

Failed merges:

r? @ghost
This commit is contained in:
bors 2020-02-07 17:47:11 +00:00
commit a29424a226
58 changed files with 679 additions and 202 deletions

4
.github/ISSUE_TEMPLATE/blank_issue.md vendored Normal file
View File

@ -0,0 +1,4 @@
---
name: Blank Issue
about: Create a blank issue.
---

44
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@ -0,0 +1,44 @@
---
name: Bug Report
about: Create a bug report for Rust.
labels: C-bug
---
<!--
Thank you for filing a bug report! 🐛 Please provide a short summary of the bug,
along with any information you feel relevant to replicating the bug.
-->
I tried this code:
```rust
<code>
```
I expected to see this happen: *explanation*
Instead, this happened: *explanation*
### Meta
<!--
If you're using the stable version of the compiler, you should also check if the
bug also exists in the beta or nightly versions.
-->
`rustc --version --verbose`:
```
<version>
```
<!--
Include a backtrace in the code block by setting `RUST_BACKTRACE=1` in your
environment. E.g. `RUST_BACKTRACE=1 cargo build`.
-->
<details><summary>Backtrace</summary>
<p>
```
<backtrace>
```
</p>
</details>

5
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@ -0,0 +1,5 @@
blank_issues_enabled: true
contact_links:
- name: Rust Programming Language Forum
url: https://users.rust-lang.org
about: Please ask and answer questions about Rust here.

52
.github/ISSUE_TEMPLATE/ice.md vendored Normal file
View File

@ -0,0 +1,52 @@
---
name: Internal Compiler Error
about: Create a report for an internal compiler error in rustc.
labels: C-bug, I-ICE, T-compiler
---
<!--
Thank you for finding an Internal Compiler Error! 🧊 If possible, try to provide
a minimal verifiable example. You can read "Rust Bug Minimization Patterns" for
how to create smaller examples.
http://blog.pnkfx.org/blog/2019/11/18/rust-bug-minimization-patterns/
-->
### Code
```
<code>
```
### Meta
<!--
If you're using the stable version of the compiler, you should also check if the
bug also exists in the beta or nightly versions.
-->
`rustc --version --verbose`:
```
<version>
```
### Error output
```
<output>
```
<!--
Include a backtrace in the code block by setting `RUST_BACKTRACE=1` in your
environment. E.g. `RUST_BACKTRACE=1 cargo build`.
-->
<details><summary><strong>Backtrace</strong></summary>
<p>
```
<backtrace>
```
</p>
</details>

View File

@ -0,0 +1,58 @@
---
name: Tracking Issue
about: A tracking issue for a feature in Rust.
title: Tracking Issue for XXX
labels: C-tracking-issue
---
<!--
Thank you for creating a tracking issue! 📜 Tracking issues are for tracking a
feature from implementation to stabilisation. Make sure to include the relevant
RFC for the feature if it has one. Otherwise provide a short summary of the
feature and link any relevant PRs or issues, and remove any sections that are
not relevant to the feature.
Remember to add team labels to the tracking issue.
For a language team feature, this would e.g., be `T-lang`.
Such a feature should also be labeled with e.g., `F-my_feature`.
This label is used to associate issues (e.g., bugs and design questions) to the feature.
-->
This is a tracking issue for the RFC "XXX" (rust-lang/rfcs#NNN).
The feature gate for the issue is `#![feature(FFF)]`.
### About tracking issues
Tracking issues are used to record the overall progress of implementation.
They are also uses as hubs connecting to other relevant issues, e.g., bugs or open design questions.
A tracking issue is however *not* meant for large scale discussion, questions, or bug reports about a feature.
Instead, open a dedicated issue for the specific matter and add the relevant feature gate label.
### Steps
<!--
Include each step required to complete the feature. Typically this is a PR
implementing a feature, followed by a PR that stabilises the feature. However
for larger features an implementation could be broken up into multiple PRs.
-->
- [ ] Implement the RFC (cc @rust-lang/XXX -- can anyone write up mentoring
instructions?)
- [ ] Adjust documentation ([see instructions on rustc-guide][doc-guide])
- [ ] Stabilization PR ([see instructions on rustc-guide][stabilization-guide])
[stabilization-guide]: https://rust-lang.github.io/rustc-guide/stabilization_guide.html#stabilization-pr
[doc-guide]: https://rust-lang.github.io/rustc-guide/stabilization_guide.html#documentation-prs
### Unresolved Questions
<!--
Include any open questions that need to be answered before the feature can be
stabilised.
-->
XXX --- list all the "unresolved questions" found in the RFC to ensure they are
not forgotten
### Implementation history
<!--
Include a list of all the PRs that were involved in implementing the feature.
-->

View File

@ -100,6 +100,7 @@ Graydon Hoare <graydon@pobox.com> Graydon Hoare <graydon@mozilla.com>
Guillaume Gomez <guillaume1.gomez@gmail.com>
Guillaume Gomez <guillaume1.gomez@gmail.com> ggomez <ggomez@ggo.ifr.lan>
Guillaume Gomez <guillaume1.gomez@gmail.com> Guillaume Gomez <ggomez@ggo.ifr.lan>
Hanna Kruppe <hanna.kruppe@gmail.com> <robin.kruppe@gmail.com>
Heather <heather@cynede.net> <Cynede@Gentoo.org>
Heather <heather@cynede.net> <Heather@cynede.net>
Herman J. Radtke III <herman@hermanradtke.com> Herman J. Radtke III <hermanradtke@gmail.com>

View File

@ -0,0 +1,29 @@
# `no_sanitize`
The tracking issue for this feature is: [#39699]
[#39699]: https://github.com/rust-lang/rust/issues/39699
------------------------
The `no_sanitize` attribute can be used to selectively disable sanitizer
instrumentation in an annotated function. This might be useful to: avoid
instrumentation overhead in a performance critical function, or avoid
instrumenting code that contains constructs unsupported by given sanitizer.
The precise effect of this annotation depends on particular sanitizer in use.
For example, with `no_sanitize(thread)`, the thread sanitizer will no longer
instrument non-atomic store / load operations, but it will instrument atomic
operations to avoid reporting false positives and provide meaning full stack
traces.
## Examples
``` rust
#![feature(no_sanitize)]
#[no_sanitize(address)]
fn foo() {
// ...
}
```

View File

@ -127,7 +127,7 @@ macro_rules! arena_types {
[] tys: rustc::ty::TyS<$tcx>,
// HIR types
[few] hir_forest: rustc::hir::map::Forest<$tcx>,
[few] hir_krate: rustc_hir::Crate<$tcx>,
[] arm: rustc_hir::Arm<$tcx>,
[] attribute: syntax::ast::Attribute,
[] block: rustc_hir::Block<$tcx>,

View File

@ -35,7 +35,7 @@
//! "infer" some properties for each kind of `DepNode`:
//!
//! * Whether a `DepNode` of a given kind has any parameters at all. Some
//! `DepNode`s, like `Krate`, represent global concepts with only one value.
//! `DepNode`s, like `AllLocalTraitImpls`, represent global concepts with only one value.
//! * Whether it is possible, in principle, to reconstruct a query key from a
//! given `DepNode`. Many `DepKind`s only require a single `DefId` parameter,
//! in which case it is possible to map the node's fingerprint back to the
@ -400,19 +400,6 @@ rustc_dep_node_append!([define_dep_nodes!][ <'tcx>
// We use this for most things when incr. comp. is turned off.
[] Null,
// Represents the `Krate` as a whole (the `hir::Krate` value) (as
// distinct from the krate module). This is basically a hash of
// the entire krate, so if you read from `Krate` (e.g., by calling
// `tcx.hir().krate()`), we will have to assume that any change
// means that you need to be recompiled. This is because the
// `Krate` value gives you access to all other items. To avoid
// this fate, do not call `tcx.hir().krate()`; instead, prefer
// wrappers like `tcx.visit_all_items_in_krate()`. If there is no
// suitable wrapper, you can use `tcx.dep_graph.ignore()` to gain
// access to the krate, but you must remember to add suitable
// edges yourself for the individual items that you read.
[eval_always] Krate,
// Represents the body of a function or method. The def-id is that of the
// function/method.
[eval_always] HirBody(DefId),

View File

@ -223,12 +223,9 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> {
(commandline_args_hash, crate_disambiguator.to_fingerprint()),
);
let (_, crate_hash) = input_dep_node_and_hash(
self.dep_graph,
&mut self.hcx,
DepNode::new_no_params(DepKind::Krate),
crate_hash_input,
);
let mut stable_hasher = StableHasher::new();
crate_hash_input.hash_stable(&mut self.hcx, &mut stable_hasher);
let crate_hash: Fingerprint = stable_hasher.finish();
let svh = Svh::new(crate_hash.to_smaller_hash());
(self.map, svh)

View File

@ -12,7 +12,7 @@ pub fn check_crate(hir_map: &Map<'_>) {
let errors = Lock::new(Vec::new());
par_iter(&hir_map.krate().modules).for_each(|(module_id, _)| {
par_iter(&hir_map.krate.modules).for_each(|(module_id, _)| {
let local_def_id = hir_map.local_def_id(*module_id);
hir_map.visit_item_likes_in_module(
local_def_id,

View File

@ -129,30 +129,6 @@ impl<'hir> Entry<'hir> {
}
}
/// Stores a crate and any number of inlined items from other crates.
pub struct Forest<'hir> {
krate: Crate<'hir>,
pub dep_graph: DepGraph,
}
impl Forest<'hir> {
pub fn new(krate: Crate<'hir>, dep_graph: &DepGraph) -> Forest<'hir> {
Forest { krate, dep_graph: dep_graph.clone() }
}
pub fn krate(&self) -> &Crate<'hir> {
self.dep_graph.read(DepNode::new_no_params(DepKind::Krate));
&self.krate
}
/// This is used internally in the dependency tracking system.
/// Use the `krate` method to ensure your dependency on the
/// crate is tracked.
pub fn untracked_krate(&self) -> &Crate<'hir> {
&self.krate
}
}
/// This type is effectively a `HashMap<HirId, Entry<'hir>>`,
/// but it is implemented as 2 layers of arrays.
/// - first we have `A = IndexVec<DefIndex, B>` mapping `DefIndex`s to an inner value
@ -162,11 +138,8 @@ pub(super) type HirEntryMap<'hir> = IndexVec<DefIndex, IndexVec<ItemLocalId, Opt
/// Represents a mapping from `NodeId`s to AST elements and their parent `NodeId`s.
#[derive(Clone)]
pub struct Map<'hir> {
/// The backing storage for all the AST nodes.
pub forest: &'hir Forest<'hir>,
krate: &'hir Crate<'hir>,
/// Same as the dep_graph in forest, just available with one fewer
/// deref. This is a gratuitous micro-optimization.
pub dep_graph: DepGraph,
/// The SVH of the local crate.
@ -217,6 +190,13 @@ impl<'hir> Iterator for ParentHirIterator<'_, 'hir> {
}
impl<'hir> Map<'hir> {
/// This is used internally in the dependency tracking system.
/// Use the `krate` method to ensure your dependency on the
/// crate is tracked.
pub fn untracked_krate(&self) -> &Crate<'hir> {
&self.krate
}
#[inline]
fn lookup(&self, id: HirId) -> Option<&Entry<'hir>> {
let local_map = self.map.get(id.owner)?;
@ -401,40 +381,36 @@ impl<'hir> Map<'hir> {
self.lookup(id).cloned()
}
pub fn krate(&self) -> &'hir Crate<'hir> {
self.forest.krate()
}
pub fn item(&self, id: HirId) -> &'hir Item<'hir> {
self.read(id);
// N.B., intentionally bypass `self.forest.krate()` so that we
// N.B., intentionally bypass `self.krate()` so that we
// do not trigger a read of the whole krate here
self.forest.krate.item(id)
self.krate.item(id)
}
pub fn trait_item(&self, id: TraitItemId) -> &'hir TraitItem<'hir> {
self.read(id.hir_id);
// N.B., intentionally bypass `self.forest.krate()` so that we
// N.B., intentionally bypass `self.krate()` so that we
// do not trigger a read of the whole krate here
self.forest.krate.trait_item(id)
self.krate.trait_item(id)
}
pub fn impl_item(&self, id: ImplItemId) -> &'hir ImplItem<'hir> {
self.read(id.hir_id);
// N.B., intentionally bypass `self.forest.krate()` so that we
// N.B., intentionally bypass `self.krate()` so that we
// do not trigger a read of the whole krate here
self.forest.krate.impl_item(id)
self.krate.impl_item(id)
}
pub fn body(&self, id: BodyId) -> &'hir Body<'hir> {
self.read(id.hir_id);
// N.B., intentionally bypass `self.forest.krate()` so that we
// N.B., intentionally bypass `self.krate()` so that we
// do not trigger a read of the whole krate here
self.forest.krate.body(id)
self.krate.body(id)
}
pub fn fn_decl_by_hir_id(&self, hir_id: HirId) -> Option<&'hir FnDecl<'hir>> {
@ -530,9 +506,9 @@ impl<'hir> Map<'hir> {
pub fn trait_impls(&self, trait_did: DefId) -> &'hir [HirId] {
self.dep_graph.read(DepNode::new_no_params(DepKind::AllLocalTraitImpls));
// N.B., intentionally bypass `self.forest.krate()` so that we
// N.B., intentionally bypass `self.krate()` so that we
// do not trigger a read of the whole krate here
self.forest.krate.trait_impls.get(&trait_did).map_or(&[], |xs| &xs[..])
self.krate.trait_impls.get(&trait_did).map_or(&[], |xs| &xs[..])
}
/// Gets the attributes on the crate. This is preferable to
@ -542,7 +518,7 @@ impl<'hir> Map<'hir> {
let def_path_hash = self.definitions.def_path_hash(CRATE_DEF_INDEX);
self.dep_graph.read(def_path_hash.to_dep_node(DepKind::Hir));
&self.forest.krate.attrs
&self.krate.attrs
}
pub fn get_module(&self, module: DefId) -> (&'hir Mod<'hir>, Span, HirId) {
@ -550,7 +526,7 @@ impl<'hir> Map<'hir> {
self.read(hir_id);
match self.find_entry(hir_id).unwrap().node {
Node::Item(&Item { span, kind: ItemKind::Mod(ref m), .. }) => (m, span, hir_id),
Node::Crate => (&self.forest.krate.module, self.forest.krate.span, hir_id),
Node::Crate => (&self.krate.module, self.krate.span, hir_id),
node => panic!("not a module: {:?}", node),
}
}
@ -567,7 +543,7 @@ impl<'hir> Map<'hir> {
// in the expect_* calls the loops below
self.read(hir_id);
let module = &self.forest.krate.modules[&hir_id];
let module = &self.krate.modules[&hir_id];
for id in &module.items {
visitor.visit_item(self.expect_item(*id));
@ -984,7 +960,7 @@ impl<'hir> Map<'hir> {
// Unit/tuple structs/variants take the attributes straight from
// the struct/variant definition.
Some(Node::Ctor(..)) => return self.attrs(self.get_parent_item(id)),
Some(Node::Crate) => Some(&self.forest.krate.attrs[..]),
Some(Node::Crate) => Some(&self.krate.attrs[..]),
_ => None,
};
attrs.unwrap_or(&[])
@ -1063,7 +1039,7 @@ impl<'hir> Map<'hir> {
Some(Node::Visibility(v)) => bug!("unexpected Visibility {:?}", v),
Some(Node::Local(local)) => local.span,
Some(Node::MacroDef(macro_def)) => macro_def.span,
Some(Node::Crate) => self.forest.krate.span,
Some(Node::Crate) => self.krate.span,
None => bug!("hir::map::Map::span: id not in map: {:?}", hir_id),
}
}
@ -1231,7 +1207,8 @@ impl Named for ImplItem<'_> {
pub fn map_crate<'hir>(
sess: &rustc_session::Session,
cstore: &CrateStoreDyn,
forest: &'hir Forest<'hir>,
krate: &'hir Crate<'hir>,
dep_graph: DepGraph,
definitions: Definitions,
) -> Map<'hir> {
let _prof_timer = sess.prof.generic_activity("build_hir_map");
@ -1244,31 +1221,18 @@ pub fn map_crate<'hir>(
.collect();
let (map, crate_hash) = {
let hcx = crate::ich::StableHashingContext::new(sess, &forest.krate, &definitions, cstore);
let hcx = crate::ich::StableHashingContext::new(sess, krate, &definitions, cstore);
let mut collector = NodeCollector::root(
sess,
&forest.krate,
&forest.dep_graph,
&definitions,
&hir_to_node_id,
hcx,
);
intravisit::walk_crate(&mut collector, &forest.krate);
let mut collector =
NodeCollector::root(sess, krate, &dep_graph, &definitions, &hir_to_node_id, hcx);
intravisit::walk_crate(&mut collector, krate);
let crate_disambiguator = sess.local_crate_disambiguator();
let cmdline_args = sess.opts.dep_tracking_hash();
collector.finalize_and_compute_crate_hash(crate_disambiguator, cstore, cmdline_args)
};
let map = Map {
forest,
dep_graph: forest.dep_graph.clone(),
crate_hash,
map,
hir_to_node_id,
definitions,
};
let map = Map { krate, dep_graph, crate_hash, map, hir_to_node_id, definitions };
sess.time("validate_HIR_map", || {
hir_id_validator::check_crate(&map);

View File

@ -7,7 +7,48 @@ pub mod exports;
pub mod map;
use crate::ty::query::Providers;
use crate::ty::TyCtxt;
use rustc_hir::def_id::LOCAL_CRATE;
use rustc_hir::print;
use rustc_hir::Crate;
use std::ops::Deref;
/// A wrapper type which allows you to access HIR.
#[derive(Clone)]
pub struct Hir<'tcx> {
tcx: TyCtxt<'tcx>,
map: &'tcx map::Map<'tcx>,
}
impl<'tcx> Hir<'tcx> {
pub fn krate(&self) -> &'tcx Crate<'tcx> {
self.tcx.hir_crate(LOCAL_CRATE)
}
}
impl<'tcx> Deref for Hir<'tcx> {
type Target = &'tcx map::Map<'tcx>;
#[inline(always)]
fn deref(&self) -> &Self::Target {
&self.map
}
}
impl<'hir> print::PpAnn for Hir<'hir> {
fn nested(&self, state: &mut print::State<'_>, nested: print::Nested) {
self.map.nested(state, nested)
}
}
impl<'tcx> TyCtxt<'tcx> {
#[inline(always)]
pub fn hir(self) -> Hir<'tcx> {
Hir { tcx: self, map: &self.hir_map }
}
}
pub fn provide(providers: &mut Providers<'_>) {
providers.hir_crate = |tcx, _| tcx.hir_map.untracked_krate();
map::provide(providers);
}

View File

@ -12,13 +12,6 @@ use smallvec::SmallVec;
impl<'ctx> rustc_target::HashStableContext for StableHashingContext<'ctx> {}
impl<'a> HashStable<StableHashingContext<'a>> for ast::Lifetime {
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
self.id.hash_stable(hcx, hasher);
self.ident.hash_stable(hcx, hasher);
}
}
impl<'a> HashStable<StableHashingContext<'a>> for [ast::Attribute] {
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
if self.len() == 0 {

View File

@ -72,6 +72,14 @@ bitflags! {
const FFI_RETURNS_TWICE = 1 << 10;
/// `#[track_caller]`: allow access to the caller location
const TRACK_CALLER = 1 << 11;
/// `#[no_sanitize(address)]`: disables address sanitizer instrumentation
const NO_SANITIZE_ADDRESS = 1 << 12;
/// `#[no_sanitize(memory)]`: disables memory sanitizer instrumentation
const NO_SANITIZE_MEMORY = 1 << 13;
/// `#[no_sanitize(thread)]`: disables thread sanitizer instrumentation
const NO_SANITIZE_THREAD = 1 << 14;
/// All `#[no_sanitize(...)]` attributes.
const NO_SANITIZE_ANY = Self::NO_SANITIZE_ADDRESS.bits | Self::NO_SANITIZE_MEMORY.bits | Self::NO_SANITIZE_THREAD.bits;
}
}

View File

@ -43,6 +43,18 @@ rustc_queries! {
}
Other {
// Represents crate as a whole (as distinct from the top-level crate module).
// If you call `hir_crate` (e.g., indirectly by calling `tcx.hir().krate()`),
// we will have to assume that any change means that you need to be recompiled.
// This is because the `hir_crate` query gives you access to all other items.
// To avoid this fate, do not call `tcx.hir().krate()`; instead,
// prefer wrappers like `tcx.visit_all_items_in_krate()`.
query hir_crate(key: CrateNum) -> &'tcx Crate<'tcx> {
eval_always
no_hash
desc { "get the crate HIR" }
}
/// Records the type of every item.
query type_of(key: DefId) -> Ty<'tcx> {
cache_on_disk_if { key.is_local() }

View File

@ -966,7 +966,8 @@ pub struct GlobalCtxt<'tcx> {
/// Export map produced by name resolution.
export_map: FxHashMap<DefId, Vec<Export<hir::HirId>>>,
hir_map: hir_map::Map<'tcx>,
/// This should usually be accessed with the `tcx.hir()` method.
pub(crate) hir_map: hir_map::Map<'tcx>,
/// A map from `DefPathHash` -> `DefId`. Includes `DefId`s from the local crate
/// as well as all upstream crates. Only populated in incremental mode.
@ -1019,11 +1020,6 @@ pub struct GlobalCtxt<'tcx> {
}
impl<'tcx> TyCtxt<'tcx> {
#[inline(always)]
pub fn hir(self) -> &'tcx hir_map::Map<'tcx> {
&self.hir_map
}
pub fn alloc_steal_mir(self, mir: BodyAndCache<'tcx>) -> &'tcx Steal<BodyAndCache<'tcx>> {
self.arena.alloc(Steal::new(mir))
}
@ -1328,7 +1324,7 @@ impl<'tcx> TyCtxt<'tcx> {
#[inline(always)]
pub fn create_stable_hashing_context(self) -> StableHashingContext<'tcx> {
let krate = self.gcx.hir_map.forest.untracked_krate();
let krate = self.gcx.hir_map.untracked_krate();
StableHashingContext::new(self.sess, krate, self.hir().definitions(), &*self.cstore)
}

View File

@ -45,7 +45,7 @@ use rustc_data_structures::sync::Lrc;
use rustc_hir as hir;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefIdSet, DefIndex};
use rustc_hir::{HirIdSet, ItemLocalId, TraitCandidate};
use rustc_hir::{Crate, HirIdSet, ItemLocalId, TraitCandidate};
use rustc_index::vec::IndexVec;
use rustc_target::spec::PanicStrategy;

View File

@ -1177,7 +1177,6 @@ pub fn force_from_dep_node(tcx: TyCtxt<'_>, dep_node: &DepNode) -> bool {
// These are inputs that are expected to be pre-allocated and that
// should therefore always be red or green already.
DepKind::AllLocalTraitImpls |
DepKind::Krate |
DepKind::CrateMetadata |
DepKind::HirBody |
DepKind::Hir |

View File

@ -46,6 +46,31 @@ fn inline(cx: &CodegenCx<'ll, '_>, val: &'ll Value, inline: InlineAttr) {
};
}
/// Apply LLVM sanitize attributes.
#[inline]
pub fn sanitize(cx: &CodegenCx<'ll, '_>, codegen_fn_flags: CodegenFnAttrFlags, llfn: &'ll Value) {
if let Some(ref sanitizer) = cx.tcx.sess.opts.debugging_opts.sanitizer {
match *sanitizer {
Sanitizer::Address => {
if !codegen_fn_flags.contains(CodegenFnAttrFlags::NO_SANITIZE_ADDRESS) {
llvm::Attribute::SanitizeAddress.apply_llfn(Function, llfn);
}
}
Sanitizer::Memory => {
if !codegen_fn_flags.contains(CodegenFnAttrFlags::NO_SANITIZE_MEMORY) {
llvm::Attribute::SanitizeMemory.apply_llfn(Function, llfn);
}
}
Sanitizer::Thread => {
if !codegen_fn_flags.contains(CodegenFnAttrFlags::NO_SANITIZE_THREAD) {
llvm::Attribute::SanitizeThread.apply_llfn(Function, llfn);
}
}
Sanitizer::Leak => {}
}
}
}
/// Tell LLVM to emit or not emit the information necessary to unwind the stack for the function.
#[inline]
pub fn emit_uwtable(val: &'ll Value, emit: bool) {
@ -288,6 +313,7 @@ pub fn from_fn_attrs(
if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::ALLOCATOR) {
Attribute::NoAlias.apply_llfn(llvm::AttributePlace::ReturnValue, llfn);
}
sanitize(cx, codegen_fn_attrs.flags, llfn);
unwind(
llfn,

View File

@ -15,6 +15,7 @@
use super::ModuleLlvm;
use crate::attributes;
use crate::builder::Builder;
use crate::common;
use crate::context::CodegenCx;
@ -23,7 +24,7 @@ use crate::metadata;
use crate::value::Value;
use rustc::dep_graph;
use rustc::middle::codegen_fn_attrs::CodegenFnAttrs;
use rustc::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
use rustc::middle::cstore::EncodedMetadata;
use rustc::middle::exported_symbols;
use rustc::mir::mono::{Linkage, Visibility};
@ -131,7 +132,9 @@ pub fn compile_codegen_unit(
// If this codegen unit contains the main function, also create the
// wrapper here
maybe_create_entry_wrapper::<Builder<'_, '_, '_>>(&cx);
if let Some(entry) = maybe_create_entry_wrapper::<Builder<'_, '_, '_>>(&cx) {
attributes::sanitize(&cx, CodegenFnAttrFlags::empty(), entry);
}
// Run replace-all-uses-with for statics that need it
for &(old_g, new_g) in cx.statics_to_rauw().borrow().iter() {

View File

@ -19,7 +19,6 @@ use crate::llvm::AttributePlace::Function;
use crate::type_::Type;
use crate::value::Value;
use log::debug;
use rustc::session::config::Sanitizer;
use rustc::ty::Ty;
use rustc_codegen_ssa::traits::*;
use rustc_data_structures::small_c_str::SmallCStr;
@ -47,21 +46,6 @@ fn declare_raw_fn(
llvm::Attribute::NoRedZone.apply_llfn(Function, llfn);
}
if let Some(ref sanitizer) = cx.tcx.sess.opts.debugging_opts.sanitizer {
match *sanitizer {
Sanitizer::Address => {
llvm::Attribute::SanitizeAddress.apply_llfn(Function, llfn);
}
Sanitizer::Memory => {
llvm::Attribute::SanitizeMemory.apply_llfn(Function, llfn);
}
Sanitizer::Thread => {
llvm::Attribute::SanitizeThread.apply_llfn(Function, llfn);
}
_ => {}
}
}
attributes::default_optimisation_attrs(cx.tcx.sess, llfn);
attributes::non_lazy_bind(cx.sess(), llfn);
llfn

View File

@ -391,10 +391,12 @@ pub fn codegen_instance<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>(
/// Creates the `main` function which will initialize the rust runtime and call
/// users main function.
pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(cx: &'a Bx::CodegenCx) {
pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
cx: &'a Bx::CodegenCx,
) -> Option<Bx::Function> {
let (main_def_id, span) = match cx.tcx().entry_fn(LOCAL_CRATE) {
Some((def_id, _)) => (def_id, cx.tcx().def_span(def_id)),
None => return,
None => return None,
};
let instance = Instance::mono(cx.tcx(), main_def_id);
@ -402,17 +404,15 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(cx: &'
if !cx.codegen_unit().contains_item(&MonoItem::Fn(instance)) {
// We want to create the wrapper in the same codegen unit as Rust's main
// function.
return;
return None;
}
let main_llfn = cx.get_fn_addr(instance);
let et = cx.tcx().entry_fn(LOCAL_CRATE).map(|e| e.1);
match et {
Some(EntryFnType::Main) => create_entry_fn::<Bx>(cx, span, main_llfn, main_def_id, true),
Some(EntryFnType::Start) => create_entry_fn::<Bx>(cx, span, main_llfn, main_def_id, false),
None => {} // Do nothing.
}
return cx.tcx().entry_fn(LOCAL_CRATE).map(|(_, et)| {
let use_start_lang_item = EntryFnType::Start != et;
create_entry_fn::<Bx>(cx, span, main_llfn, main_def_id, use_start_lang_item)
});
fn create_entry_fn<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
cx: &'a Bx::CodegenCx,
@ -420,7 +420,7 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(cx: &'
rust_main: Bx::Value,
rust_main_def_id: DefId,
use_start_lang_item: bool,
) {
) -> Bx::Function {
// The entry function is either `int main(void)` or `int main(int argc, char **argv)`,
// depending on whether the target needs `argc` and `argv` to be passed in.
let llfty = if cx.sess().target.target.options.main_needs_argc_argv {
@ -481,6 +481,8 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(cx: &'
let result = bx.call(start_fn, &args, None);
let cast = bx.intcast(result, cx.type_int(), true);
bx.ret(cast);
llfn
}
}

View File

@ -69,19 +69,19 @@ where
match *ppmode {
PpmNormal => {
let annotation = NoAnn { sess: tcx.sess, tcx: Some(tcx) };
f(&annotation, tcx.hir().forest.krate())
f(&annotation, tcx.hir().krate())
}
PpmIdentified => {
let annotation = IdentifiedAnnotation { sess: tcx.sess, tcx: Some(tcx) };
f(&annotation, tcx.hir().forest.krate())
f(&annotation, tcx.hir().krate())
}
PpmTyped => {
abort_on_err(tcx.analysis(LOCAL_CRATE), tcx.sess);
let empty_tables = ty::TypeckTables::empty(None);
let annotation = TypedAnnotation { tcx, tables: Cell::new(&empty_tables) };
tcx.dep_graph.with_ignore(|| f(&annotation, tcx.hir().forest.krate()))
tcx.dep_graph.with_ignore(|| f(&annotation, tcx.hir().krate()))
}
_ => panic!("Should use call_with_pp_support"),
}
@ -143,7 +143,7 @@ impl<'hir> HirPrinterSupport<'hir> for NoAnn<'hir> {
}
fn hir_map<'a>(&'a self) -> Option<&'a hir_map::Map<'hir>> {
self.tcx.map(|tcx| tcx.hir())
self.tcx.map(|tcx| *tcx.hir())
}
fn pp_ann<'a>(&'a self) -> &'a dyn pprust_hir::PpAnn {
@ -155,7 +155,7 @@ impl<'hir> pprust::PpAnn for NoAnn<'hir> {}
impl<'hir> pprust_hir::PpAnn for NoAnn<'hir> {
fn nested(&self, state: &mut pprust_hir::State<'_>, nested: pprust_hir::Nested) {
if let Some(tcx) = self.tcx {
pprust_hir::PpAnn::nested(tcx.hir(), state, nested)
pprust_hir::PpAnn::nested(*tcx.hir(), state, nested)
}
}
}
@ -217,7 +217,7 @@ impl<'hir> HirPrinterSupport<'hir> for IdentifiedAnnotation<'hir> {
}
fn hir_map<'a>(&'a self) -> Option<&'a hir_map::Map<'hir>> {
self.tcx.map(|tcx| tcx.hir())
self.tcx.map(|tcx| *tcx.hir())
}
fn pp_ann<'a>(&'a self) -> &'a dyn pprust_hir::PpAnn {
@ -228,7 +228,7 @@ impl<'hir> HirPrinterSupport<'hir> for IdentifiedAnnotation<'hir> {
impl<'hir> pprust_hir::PpAnn for IdentifiedAnnotation<'hir> {
fn nested(&self, state: &mut pprust_hir::State<'_>, nested: pprust_hir::Nested) {
if let Some(ref tcx) = self.tcx {
pprust_hir::PpAnn::nested(tcx.hir(), state, nested)
pprust_hir::PpAnn::nested(*tcx.hir(), state, nested)
}
}
fn pre(&self, s: &mut pprust_hir::State<'_>, node: pprust_hir::AnnNode<'_>) {
@ -334,7 +334,7 @@ impl<'a, 'tcx> pprust_hir::PpAnn for TypedAnnotation<'a, 'tcx> {
if let pprust_hir::Nested::Body(id) = nested {
self.tables.set(self.tcx.body_tables(id));
}
pprust_hir::PpAnn::nested(self.tcx.hir(), state, nested);
pprust_hir::PpAnn::nested(*self.tcx.hir(), state, nested);
self.tables.set(old_tables);
}
fn pre(&self, s: &mut pprust_hir::State<'_>, node: pprust_hir::AnnNode<'_>) {

View File

@ -1,5 +1,6 @@
This error occurs when a bound in an implementation of a trait does not match
the bounds specified in the original trait. For example:
A trait implementation has stricter requirements than the trait definition.
Erroneous code example:
```compile_fail,E0276
trait Foo {

View File

@ -541,6 +541,9 @@ declare_features! (
/// Allows `T: ?const Trait` syntax in bounds.
(active, const_trait_bound_opt_out, "1.42.0", Some(67794), None),
/// Allows the use of `no_sanitize` attribute.
(active, no_sanitize, "1.42.0", Some(39699), None),
// -------------------------------------------------------------------------
// feature-group-end: actual feature gates
// -------------------------------------------------------------------------

View File

@ -261,6 +261,11 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
ungated!(cold, Whitelisted, template!(Word)),
ungated!(no_builtins, Whitelisted, template!(Word)),
ungated!(target_feature, Whitelisted, template!(List: r#"enable = "name""#)),
gated!(
no_sanitize, Whitelisted,
template!(List: "address, memory, thread"),
experimental!(no_sanitize)
),
// FIXME: #14408 whitelist docs since rustdoc looks at them
ungated!(doc, Whitelisted, template!(List: "hidden|inline|...", NameValueStr: "string")),

View File

@ -25,6 +25,7 @@ use rustc_data_structures::{box_region_allow_access, declare_box_region_type, pa
use rustc_errors::PResult;
use rustc_expand::base::ExtCtxt;
use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
use rustc_hir::Crate;
use rustc_lint::LintStore;
use rustc_mir as mir;
use rustc_mir_build as mir_build;
@ -422,7 +423,7 @@ pub fn lower_to_hir<'res, 'tcx>(
dep_graph: &'res DepGraph,
krate: &'res ast::Crate,
arena: &'tcx Arena<'tcx>,
) -> Result<map::Forest<'tcx>> {
) -> Crate<'tcx> {
// Lower AST to HIR.
let hir_crate = rustc_ast_lowering::lower_crate(
sess,
@ -437,8 +438,6 @@ pub fn lower_to_hir<'res, 'tcx>(
hir_stats::print_hir_stats(&hir_crate);
}
let hir_forest = map::Forest::new(hir_crate, &dep_graph);
sess.time("early_lint_checks", || {
rustc_lint::check_ast_crate(
sess,
@ -455,7 +454,7 @@ pub fn lower_to_hir<'res, 'tcx>(
rustc_span::hygiene::clear_syntax_context_map();
}
Ok(hir_forest)
hir_crate
}
// Returns all the paths that correspond to generated files.
@ -705,7 +704,8 @@ impl<'tcx> QueryContext<'tcx> {
pub fn create_global_ctxt<'tcx>(
compiler: &'tcx Compiler,
lint_store: Lrc<LintStore>,
hir_forest: &'tcx map::Forest<'tcx>,
krate: &'tcx Crate<'tcx>,
dep_graph: DepGraph,
mut resolver_outputs: ResolverOutputs,
outputs: OutputFilenames,
crate_name: &str,
@ -716,7 +716,7 @@ pub fn create_global_ctxt<'tcx>(
let defs = mem::take(&mut resolver_outputs.definitions);
// Construct the HIR map.
let hir_map = map::map_crate(sess, &*resolver_outputs.cstore, &hir_forest, defs);
let hir_map = map::map_crate(sess, &*resolver_outputs.cstore, krate, dep_graph, defs);
let query_result_on_disk_cache = rustc_incremental::load_query_result_cache(sess);

View File

@ -3,7 +3,6 @@ use crate::passes::{self, BoxedResolver, QueryContext};
use rustc::arena::Arena;
use rustc::dep_graph::DepGraph;
use rustc::hir::map;
use rustc::session::config::{OutputFilenames, OutputType};
use rustc::session::Session;
use rustc::ty::steal::Steal;
@ -12,6 +11,7 @@ use rustc::util::common::ErrorReported;
use rustc_codegen_utils::codegen_backend::CodegenBackend;
use rustc_data_structures::sync::{Lrc, Once, WorkerLocal};
use rustc_hir::def_id::LOCAL_CRATE;
use rustc_hir::Crate;
use rustc_incremental::DepGraphFuture;
use rustc_lint::LintStore;
use std::any::Any;
@ -74,7 +74,7 @@ pub struct Queries<'tcx> {
register_plugins: Query<(ast::Crate, Lrc<LintStore>)>,
expansion: Query<(ast::Crate, Steal<Rc<RefCell<BoxedResolver>>>, Lrc<LintStore>)>,
dep_graph: Query<DepGraph>,
lower_to_hir: Query<(&'tcx map::Forest<'tcx>, Steal<ResolverOutputs>)>,
lower_to_hir: Query<(&'tcx Crate<'tcx>, Steal<ResolverOutputs>)>,
prepare_outputs: Query<OutputFilenames>,
global_ctxt: Query<QueryContext<'tcx>>,
ongoing_codegen: Query<Box<dyn Any>>,
@ -207,9 +207,7 @@ impl<'tcx> Queries<'tcx> {
})
}
pub fn lower_to_hir(
&'tcx self,
) -> Result<&Query<(&'tcx map::Forest<'tcx>, Steal<ResolverOutputs>)>> {
pub fn lower_to_hir(&'tcx self) -> Result<&Query<(&'tcx Crate<'tcx>, Steal<ResolverOutputs>)>> {
self.lower_to_hir.compute(|| {
let expansion_result = self.expansion()?;
let peeked = expansion_result.peek();
@ -217,14 +215,14 @@ impl<'tcx> Queries<'tcx> {
let resolver = peeked.1.steal();
let lint_store = &peeked.2;
let hir = resolver.borrow_mut().access(|resolver| {
passes::lower_to_hir(
Ok(passes::lower_to_hir(
self.session(),
lint_store,
resolver,
&*self.dep_graph()?.peek(),
&krate,
&self.arena,
)
))
})?;
let hir = self.arena.alloc(hir);
Ok((hir, Steal::new(BoxedResolver::to_resolver_outputs(resolver))))
@ -253,12 +251,14 @@ impl<'tcx> Queries<'tcx> {
let outputs = self.prepare_outputs()?.peek().clone();
let lint_store = self.expansion()?.peek().2.clone();
let hir = self.lower_to_hir()?.peek();
let (ref hir_forest, ref resolver_outputs) = &*hir;
let dep_graph = self.dep_graph()?.peek().clone();
let (ref krate, ref resolver_outputs) = &*hir;
let _timer = self.session().timer("create_global_ctxt");
Ok(passes::create_global_ctxt(
self.compiler,
lint_store,
hir_forest,
krate,
dep_graph,
resolver_outputs.steal(),
outputs,
&crate_name,

View File

@ -796,7 +796,7 @@ impl EncodeContext<'tcx> {
record!(self.per_def.kind[def_id] <- match trait_item.kind {
ty::AssocKind::Const => {
let rendered =
hir::print::to_string(self.tcx.hir(), |s| s.print_trait_item(ast_item));
hir::print::to_string(&self.tcx.hir(), |s| s.print_trait_item(ast_item));
let rendered_const = self.lazy(RenderedConst(rendered));
EntryKind::AssocConst(
@ -1009,7 +1009,7 @@ impl EncodeContext<'tcx> {
fn encode_rendered_const_for_body(&mut self, body_id: hir::BodyId) -> Lazy<RenderedConst> {
let body = self.tcx.hir().body(body_id);
let rendered = hir::print::to_string(self.tcx.hir(), |s| s.print_expr(&body.value));
let rendered = hir::print::to_string(&self.tcx.hir(), |s| s.print_expr(&body.value));
let rendered_const = &RenderedConst(rendered);
self.lazy(rendered_const)
}

View File

@ -8,6 +8,7 @@ use rustc_index::vec::{Idx, IndexVec};
use rustc::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use rustc::mir::visit::*;
use rustc::mir::*;
use rustc::session::config::Sanitizer;
use rustc::ty::subst::{InternalSubsts, Subst, SubstsRef};
use rustc::ty::{self, Instance, InstanceDef, ParamEnv, Ty, TyCtxt, TypeFoldable};
@ -228,6 +229,28 @@ impl Inliner<'tcx> {
return false;
}
// Avoid inlining functions marked as no_sanitize if sanitizer is enabled,
// since instrumentation might be enabled and performed on the caller.
match self.tcx.sess.opts.debugging_opts.sanitizer {
Some(Sanitizer::Address) => {
if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NO_SANITIZE_ADDRESS) {
return false;
}
}
Some(Sanitizer::Memory) => {
if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NO_SANITIZE_MEMORY) {
return false;
}
}
Some(Sanitizer::Thread) => {
if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NO_SANITIZE_THREAD) {
return false;
}
}
Some(Sanitizer::Leak) => {}
None => {}
}
let hinted = match codegen_fn_attrs.inline {
// Just treat inline(always) as a hint for now,
// there are cases that prevent inlining that we

View File

@ -8,6 +8,7 @@
//! through, but errors for structured control flow in a `const` should be emitted here.
use rustc::hir::map::Map;
use rustc::hir::Hir;
use rustc::session::config::nightly_options;
use rustc::session::parse::feature_err;
use rustc::ty::query::Providers;
@ -74,7 +75,7 @@ enum ConstKind {
}
impl ConstKind {
fn for_body(body: &hir::Body<'_>, hir_map: &Map<'_>) -> Option<Self> {
fn for_body(body: &hir::Body<'_>, hir_map: Hir<'_>) -> Option<Self> {
let is_const_fn = |id| hir_map.fn_sig_by_hir_id(id).unwrap().header.is_const();
let owner = hir_map.body_owner(body.id());

View File

@ -1,4 +1,4 @@
use rustc::hir::map as hir_map;
use rustc::hir::Hir;
use rustc::session::config::EntryFnType;
use rustc::session::{config, Session};
use rustc::ty::query::Providers;
@ -15,7 +15,7 @@ use syntax::entry::EntryPointType;
struct EntryContext<'a, 'tcx> {
session: &'a Session,
map: &'a hir_map::Map<'tcx>,
map: Hir<'tcx>,
/// The top-level function called `main`.
main_fn: Option<(HirId, Span)>,

View File

@ -612,7 +612,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
let parent_id = self.tcx.hir().get_parent_node(hir_id);
let parent_impl_id = hir::ImplItemId { hir_id: parent_id };
let parent_trait_id = hir::TraitItemId { hir_id: parent_id };
let krate = self.tcx.hir().forest.krate();
let krate = self.tcx.hir().krate();
if !(krate.items.contains_key(&parent_id)
|| krate.impl_items.contains_key(&parent_impl_id)

View File

@ -474,6 +474,12 @@ declare_lint! {
};
}
declare_lint! {
pub INLINE_NO_SANITIZE,
Warn,
"detects incompatible use of `#[inline(always)]` and `#[no_sanitize(...)]`",
}
declare_lint_pass! {
/// Does nothing as a lint pass, but registers some `Lint`s
/// that are used by other parts of the compiler.
@ -537,5 +543,6 @@ declare_lint_pass! {
MUTABLE_BORROW_RESERVATION_CONFLICT,
INDIRECT_STRUCTURAL_MATCH,
SOFT_UNSTABLE,
INLINE_NO_SANITIZE,
]
}

View File

@ -120,6 +120,7 @@ symbols! {
abi_vectorcall,
abi_x86_interrupt,
aborts,
address,
add_with_overflow,
advanced_slice_patterns,
adx_target_feature,
@ -445,6 +446,7 @@ symbols! {
mem_uninitialized,
mem_zeroed,
member_constraints,
memory,
message,
meta,
min_align_of,
@ -487,6 +489,7 @@ symbols! {
None,
non_exhaustive,
non_modrs_mods,
no_sanitize,
no_stack_check,
no_start,
no_std,
@ -721,6 +724,7 @@ symbols! {
test_removed_feature,
test_runner,
then_with,
thread,
thread_local,
tool_attributes,
tool_lints,

View File

@ -2598,7 +2598,7 @@ fn report_unexpected_variant_res(tcx: TyCtxt<'_>, res: Res, span: Span, qpath: &
E0533,
"expected unit struct, unit variant or constant, found {} `{}`",
res.descr(),
hir::print::to_string(tcx.hir(), |s| s.print_qpath(qpath, false))
hir::print::to_string(&tcx.hir(), |s| s.print_qpath(qpath, false))
)
.emit();
}

View File

@ -693,7 +693,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let msg = format!(
"expected tuple struct or tuple variant, found {} `{}`",
res.descr(),
hir::print::to_string(tcx.hir(), |s| s.print_qpath(qpath, false)),
hir::print::to_string(&tcx.hir(), |s| s.print_qpath(qpath, false)),
);
let mut err = struct_span_err!(tcx.sess, pat.span, E0164, "{}", msg);
match (res, &pat.kind) {

View File

@ -1,3 +1,5 @@
// ignore-tidy-filelength
//! "Collection" is the process of determining the type and other external
//! details of each item in Rust. Collection is specifically concerned
//! with *inter-procedural* things -- for example, for a function
@ -2743,6 +2745,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
let mut inline_span = None;
let mut link_ordinal_span = None;
let mut no_sanitize_span = None;
for attr in attrs.iter() {
if attr.check_name(sym::cold) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::COLD;
@ -2832,6 +2835,24 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
if let ordinal @ Some(_) = check_link_ordinal(tcx, attr) {
codegen_fn_attrs.link_ordinal = ordinal;
}
} else if attr.check_name(sym::no_sanitize) {
no_sanitize_span = Some(attr.span);
if let Some(list) = attr.meta_item_list() {
for item in list.iter() {
if item.check_name(sym::address) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_SANITIZE_ADDRESS;
} else if item.check_name(sym::memory) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_SANITIZE_MEMORY;
} else if item.check_name(sym::thread) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_SANITIZE_THREAD;
} else {
tcx.sess
.struct_span_err(item.span(), "invalid argument for `no_sanitize`")
.note("expected one of: `address`, `memory` or `thread`")
.emit();
}
}
}
}
}
@ -2911,7 +2932,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
// purpose functions as they wouldn't have the right target features
// enabled. For that reason we also forbid #[inline(always)] as it can't be
// respected.
if codegen_fn_attrs.target_features.len() > 0 {
if codegen_fn_attrs.inline == InlineAttr::Always {
if let Some(span) = inline_span {
@ -2924,6 +2944,22 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
}
}
if codegen_fn_attrs.flags.intersects(CodegenFnAttrFlags::NO_SANITIZE_ANY) {
if codegen_fn_attrs.inline == InlineAttr::Always {
if let (Some(no_sanitize_span), Some(inline_span)) = (no_sanitize_span, inline_span) {
let hir_id = tcx.hir().as_local_hir_id(id).unwrap();
tcx.struct_span_lint_hir(
lint::builtin::INLINE_NO_SANITIZE,
hir_id,
no_sanitize_span,
"`no_sanitize` will have no effect after inlining",
)
.span_note(inline_span, "inlining requested here")
.emit();
}
}
}
// Weak lang items have the same semantics as "std internal" symbols in the
// sense that they're preserved through all our LTO passes and only
// strippable by the linker.

View File

@ -87,7 +87,7 @@ pub fn run(options: Options) -> i32 {
compiler.enter(|queries| {
let lower_to_hir = queries.lower_to_hir()?;
let mut opts = scrape_test_config(lower_to_hir.peek().0.krate());
let mut opts = scrape_test_config(lower_to_hir.peek().0);
opts.display_warnings |= options.display_warnings;
let enable_per_target_ignores = options.enable_per_target_ignores;
let mut collector = Collector::new(
@ -107,7 +107,7 @@ pub fn run(options: Options) -> i32 {
let mut hir_collector = HirCollector {
sess: compiler.session(),
collector: &mut collector,
map: tcx.hir(),
map: *tcx.hir(),
codes: ErrorCodes::from(
compiler.session().opts.unstable_features.is_nightly_build(),
),

View File

@ -63,8 +63,7 @@ use std::{
env, io,
io::prelude::Write,
panic::{self, catch_unwind, AssertUnwindSafe, PanicInfo},
process,
process::{Command, Termination},
process::{self, Command, Termination},
sync::mpsc::{channel, Sender},
sync::{Arc, Mutex},
thread,
@ -457,9 +456,13 @@ pub fn run_test(
monitor_ch,
opts.time,
),
RunStrategy::SpawnPrimary => {
spawn_test_subprocess(desc, opts.time.is_some(), monitor_ch, opts.time)
}
RunStrategy::SpawnPrimary => spawn_test_subprocess(
desc,
opts.nocapture,
opts.time.is_some(),
monitor_ch,
opts.time,
),
};
// If the platform is single-threaded we're just going to run
@ -558,6 +561,7 @@ fn run_test_in_process(
fn spawn_test_subprocess(
desc: TestDesc,
nocapture: bool,
report_time: bool,
monitor_ch: Sender<CompletedTest>,
time_opts: Option<time::TestTimeOptions>,
@ -566,11 +570,15 @@ fn spawn_test_subprocess(
let args = env::args().collect::<Vec<_>>();
let current_exe = &args[0];
let mut command = Command::new(current_exe);
command.env(SECONDARY_TEST_INVOKER_VAR, desc.name.as_slice());
if nocapture {
command.stdout(process::Stdio::inherit());
command.stderr(process::Stdio::inherit());
}
let start = report_time.then(Instant::now);
let output = match Command::new(current_exe)
.env(SECONDARY_TEST_INVOKER_VAR, desc.name.as_slice())
.output()
{
let output = match command.output() {
Ok(out) => out,
Err(e) => {
let err = format!("Failed to spawn {} as child for test: {:?}", args[0], e);

View File

@ -0,0 +1,32 @@
// Verifies that no_sanitize attribute prevents inlining when
// given sanitizer is enabled, but has no effect on inlining otherwise.
//
// needs-sanitizer-support
// only-x86_64
//
// revisions: ASAN LSAN
//
//[ASAN] compile-flags: -Zsanitizer=address -C opt-level=3 -Z mir-opt-level=3
//[LSAN] compile-flags: -Zsanitizer=leak -C opt-level=3 -Z mir-opt-level=3
#![crate_type="lib"]
#![feature(no_sanitize)]
// ASAN-LABEL: define void @test
// ASAN: tail call fastcc void @random_inline
// ASAN: }
//
// LSAN-LABEL: define void @test
// LSAN-NO: call
// LSAN: }
#[no_mangle]
pub fn test(n: &mut u32) {
random_inline(n);
}
#[no_sanitize(address)]
#[inline]
#[no_mangle]
pub fn random_inline(n: &mut u32) {
*n = 42;
}

View File

@ -0,0 +1,29 @@
// Verifies that no_sanitze attribute can be used to
// selectively disable sanitizer instrumentation.
//
// needs-sanitizer-support
// compile-flags: -Zsanitizer=address
#![crate_type="lib"]
#![feature(no_sanitize)]
// CHECK-LABEL: ; sanitizer_no_sanitize::unsanitized
// CHECK-NEXT: ; Function Attrs:
// CHECK-NOT: sanitize_address
// CHECK: start:
// CHECK-NOT: call void @__asan_report_load
// CHECK: }
#[no_sanitize(address)]
pub fn unsanitized(b: &mut u8) -> u8 {
*b
}
// CHECK-LABEL: ; sanitizer_no_sanitize::sanitized
// CHECK-NEXT: ; Function Attrs:
// CHECK: sanitize_address
// CHECK: start:
// CHECK: call void @__asan_report_load
// CHECK: }
pub fn sanitized(b: &mut u8) -> u8 {
*b
}

View File

@ -7,11 +7,9 @@
// Check that reordering otherwise identical items is not considered a
// change at all.
#[rustc_clean(label="Krate", cfg="rpass2")]
#[rustc_clean(label = "hir_crate", cfg = "rpass2")]
// But removing an item, naturally, is.
#[rustc_dirty(label="Krate", cfg="rpass3")]
#[rustc_dirty(label = "hir_crate", cfg = "rpass3")]
#[cfg(rpass1)]
pub struct X {
pub x: u32,
@ -26,4 +24,4 @@ pub struct X {
pub x: u32,
}
pub fn main() { }
pub fn main() {}

View File

@ -1,18 +1,14 @@
// Test that debuginfo does not introduce a dependency edge to the Krate
// Test that debuginfo does not introduce a dependency edge to the hir_crate
// dep-node.
// revisions:rpass1 rpass2
// compile-flags: -Z query-dep-graph
#![feature(rustc_attrs)]
#![rustc_partition_reused(module="issue_38222-mod1", cfg="rpass2")]
// If codegen had added a dependency edge to the Krate dep-node, nothing would
#![rustc_partition_reused(module = "issue_38222-mod1", cfg = "rpass2")]
// If codegen had added a dependency edge to the hir_crate dep-node, nothing would
// be re-used, so checking that this module was re-used is sufficient.
#![rustc_partition_reused(module="issue_38222", cfg="rpass2")]
#![rustc_partition_reused(module = "issue_38222", cfg = "rpass2")]
//[rpass1] compile-flags: -C debuginfo=1
//[rpass2] compile-flags: -C debuginfo=1

View File

@ -4,20 +4,20 @@
#![allow(warnings)]
#![feature(rustc_attrs)]
#![rustc_partition_reused(module="krate_inherent-x", cfg="cfail2")]
#![rustc_partition_reused(module = "krate_inherent-x", cfg = "cfail2")]
#![crate_type = "rlib"]
pub mod x {
pub struct Foo;
impl Foo {
pub fn foo(&self) { }
pub fn foo(&self) {}
}
pub fn method() {
let x: Foo = Foo;
x.foo(); // inherent methods used to add an edge from Krate
x.foo(); // inherent methods used to add an edge from hir_crate
}
}
#[cfg(cfail1)]
pub fn bar() { } // remove this unrelated fn in cfail2, which should not affect `x::method`
pub fn bar() {} // remove this unrelated fn in cfail2, which should not affect `x::method`

View File

@ -1,5 +1,5 @@
// Regr. test that using HIR inlined from another krate does *not* add
// a dependency from the local Krate node. We can't easily test that
// a dependency from the local hir_crate node. We can't easily test that
// directly anymore, so now we test that we get reuse.
// revisions: rpass1 rpass2
@ -7,7 +7,7 @@
#![allow(warnings)]
#![feature(rustc_attrs)]
#![rustc_partition_reused(module="krate_inlined-x", cfg="rpass2")]
#![rustc_partition_reused(module = "krate_inlined-x", cfg = "rpass2")]
fn main() {
x::method();

View File

@ -6,17 +6,16 @@
#![feature(rustc_attrs)]
#![allow(dead_code)]
#![allow(unused_variables)]
fn main() { }
#![rustc_if_this_changed(hir_crate)]
fn main() {}
struct Foo<T> {
f: T
f: T,
}
#[rustc_if_this_changed(Krate)]
type TypeAlias<T> = Foo<T>;
#[rustc_then_this_would_need(variances_of)] //~ ERROR OK
struct Use<T> {
x: TypeAlias<T>
x: TypeAlias<T>,
}

View File

@ -1,5 +1,5 @@
error: OK
--> $DIR/dep-graph-variance-alias.rs:19:1
--> $DIR/dep-graph-variance-alias.rs:18:1
|
LL | #[rustc_then_this_would_need(variances_of)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

View File

@ -0,0 +1,4 @@
#[no_sanitize(address)]
//~^ the `#[no_sanitize]` attribute is an experimental feature
fn main() {
}

View File

@ -0,0 +1,12 @@
error[E0658]: the `#[no_sanitize]` attribute is an experimental feature
--> $DIR/feature-gate-no_sanitize.rs:1:1
|
LL | #[no_sanitize(address)]
| ^^^^^^^^^^^^^^^^^^^^^^^
|
= note: for more information, see https://github.com/rust-lang/rust/issues/39699
= help: add `#![feature(no_sanitize)]` to the crate attributes to enable
error: aborting due to previous error
For more information about this error, try `rustc --explain E0658`.

View File

@ -0,0 +1,5 @@
#![feature(no_sanitize)]
#[no_sanitize(brontosaurus)] //~ ERROR invalid argument
fn main() {
}

View File

@ -0,0 +1,10 @@
error: invalid argument for `no_sanitize`
--> $DIR/invalid-no-sanitize.rs:3:15
|
LL | #[no_sanitize(brontosaurus)]
| ^^^^^^^^^^^^
|
= note: expected one of: `address`, `memory` or `thread`
error: aborting due to previous error

View File

@ -0,0 +1,15 @@
// check-pass
#![feature(no_sanitize)]
#[inline(always)]
//~^ NOTE inlining requested here
#[no_sanitize(address)]
//~^ WARN will have no effect after inlining
//~| NOTE on by default
fn x() {
}
fn main() {
x()
}

View File

@ -0,0 +1,13 @@
warning: `no_sanitize` will have no effect after inlining
--> $DIR/sanitize-inline-always.rs:7:1
|
LL | #[no_sanitize(address)]
| ^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `#[warn(inline_no_sanitize)]` on by default
note: inlining requested here
--> $DIR/sanitize-inline-always.rs:5:1
|
LL | #[inline(always)]
| ^^^^^^^^^^^^^^^^^

View File

@ -0,0 +1,39 @@
// no-prefer-dynamic
// compile-flags: --test -Cpanic=abort -Zpanic_abort_tests
// run-flags: --test-threads=1 --nocapture
// run-fail
// check-run-results
// exec-env:RUST_BACKTRACE=0
// ignore-wasm no panic or subprocess support
// ignore-emscripten no panic or subprocess support
#![cfg(test)]
use std::io::Write;
#[test]
fn it_works() {
println!("about to succeed");
assert_eq!(1 + 1, 2);
}
#[test]
#[should_panic]
fn it_panics() {
println!("about to panic");
assert_eq!(1 + 1, 4);
}
#[test]
fn it_fails() {
println!("about to fail");
assert_eq!(1 + 1, 4);
}
#[test]
fn it_writes_to_stdio() {
println!("hello, world");
writeln!(std::io::stdout(), "testing123").unwrap();
writeln!(std::io::stderr(), "testing321").unwrap();
}

View File

@ -0,0 +1,9 @@
thread 'main' panicked at 'assertion failed: `(left == right)`
left: `2`,
right: `4`', $DIR/test-panic-abort-nocapture.rs:31:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
thread 'main' panicked at 'assertion failed: `(left == right)`
left: `2`,
right: `4`', $DIR/test-panic-abort-nocapture.rs:25:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
testing321

View File

@ -0,0 +1,23 @@
running 4 tests
test it_fails ... about to fail
FAILED
test it_panics ... about to panic
ok
test it_works ... about to succeed
ok
test it_writes_to_stdio ... hello, world
testing123
ok
failures:
---- it_fails stdout ----
---- it_fails stderr ----
failures:
it_fails
test result: FAILED. 3 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out