# =============================================================================
[rust]
-# Indicates that the build should be optimized for debugging Rust. Note that
-# this is typically not what you want as it takes an incredibly large amount of
-# time to have a debug-mode rustc compile any code (notably libstd). If this
-# value is set to `true` it will affect a number of configuration options below
-# as well, if unconfigured.
-#debug = false
-
-# Whether or not to optimize the compiler and standard library
+# Whether or not to optimize the compiler and standard library.
+#
# Note: the slowness of the non optimized compiler compiling itself usually
# outweighs the time gains in not doing optimizations, therefore a
-# full bootstrap takes much more time with optimize set to false.
+# full bootstrap takes much more time with `optimize` set to false.
#optimize = true
+# Indicates that the build should be configured for debugging Rust. A
+# `debug`-enabled compiler and standard library will be somewhat
+# slower (due to e.g. checking of debug assertions) but should remain
+# usable.
+#
+# Note: If this value is set to `true`, it will affect a number of
+# configuration options below as well, if they have been left
+# unconfigured in this file.
+#
+# Note: changes to the `debug` setting do *not* affect `optimize`
+# above. In theory, a "maximally debuggable" environment would
+# set `optimize` to `false` above to assist the introspection
+# facilities of debuggers like lldb and gdb. To recreate such an
+# environment, explicitly set `optimize` to `false` and `debug`
+# to `true`. In practice, everyone leaves `optimize` set to
+# `true`, because an unoptimized rustc with debugging
+# enabled becomes *unusably slow* (e.g. rust-lang/rust#24840
+# reported a 25x slowdown) and bootstrapping the supposed
+# "maximally debuggable" environment (notably libstd) takes
+# hours to build.
+#
+#debug = false
+
# Number of codegen units to use for each compiler invocation. A value of 0
# means "the number of cores on this machine", and 1+ is passed through to the
# compiler.
let default = false;
config.llvm_assertions = llvm_assertions.unwrap_or(default);
+ let default = true;
+ config.rust_optimize = optimize.unwrap_or(default);
+
let default = match &config.channel[..] {
"stable" | "beta" | "nightly" => true,
_ => false,
config.debug_jemalloc = debug_jemalloc.unwrap_or(default);
config.rust_debuginfo = debuginfo.unwrap_or(default);
config.rust_debug_assertions = debug_assertions.unwrap_or(default);
- config.rust_optimize = optimize.unwrap_or(!default);
let default = config.channel == "dev";
config.ignore_git = ignore_git.unwrap_or(default);
def children(self):
(length, data_ptr) = \
rustpp.extract_length_and_ptr_from_std_btreeset(self.__val)
- val = GdbValue(data_ptr.get_wrapped_value().dereference()).get_child_at_index(3)
- gdb_ptr = val.get_wrapped_value()
+ leaf_node = GdbValue(data_ptr.get_wrapped_value().dereference())
+ maybe_uninit_keys = leaf_node.get_child_at_index(3)
+ manually_drop_keys = maybe_uninit_keys.get_child_at_index(1)
+ keys = manually_drop_keys.get_child_at_index(0)
+ gdb_ptr = keys.get_wrapped_value()
for index in xrange(length):
yield (str(index), gdb_ptr[index])
def children(self):
(length, data_ptr) = \
rustpp.extract_length_and_ptr_from_std_btreemap(self.__val)
- keys = GdbValue(data_ptr.get_wrapped_value().dereference()).get_child_at_index(3)
+ leaf_node = GdbValue(data_ptr.get_wrapped_value().dereference())
+ maybe_uninit_keys = leaf_node.get_child_at_index(3)
+ manually_drop_keys = maybe_uninit_keys.get_child_at_index(1)
+ keys = manually_drop_keys.get_child_at_index(0)
keys_ptr = keys.get_wrapped_value()
- vals = GdbValue(data_ptr.get_wrapped_value().dereference()).get_child_at_index(4)
+ maybe_uninit_vals = leaf_node.get_child_at_index(4)
+ manually_drop_vals = maybe_uninit_vals.get_child_at_index(1)
+ vals = manually_drop_vals.get_child_at_index(0)
vals_ptr = vals.get_wrapped_value()
for index in xrange(length):
yield (str(index), keys_ptr[index])
// This implies that even an empty internal node has at least one edge.
use core::marker::PhantomData;
-use core::mem;
+use core::mem::{self, MaybeUninit};
use core::ptr::{self, Unique, NonNull};
use core::slice;
/// these should always be put behind pointers, and specifically behind `BoxedNode` in the owned
/// case.
///
-/// See also rust-lang/rfcs#197, which would make this structure significantly more safe by
-/// avoiding accidentally dropping unused and uninitialized keys and values.
-///
/// We put the metadata first so that its position is the same for every `K` and `V`, in order
/// to statically allocate a single dummy node to avoid allocations. This struct is `repr(C)` to
/// prevent them from being reordered.
/// This node's index into the parent node's `edges` array.
/// `*node.parent.edges[node.parent_idx]` should be the same thing as `node`.
/// This is only guaranteed to be initialized when `parent` is nonnull.
- parent_idx: u16,
+ parent_idx: MaybeUninit<u16>,
/// The number of keys and values this node stores.
///
/// The arrays storing the actual data of the node. Only the first `len` elements of each
/// array are initialized and valid.
- keys: [K; CAPACITY],
- vals: [V; CAPACITY],
+ keys: MaybeUninit<[K; CAPACITY]>,
+ vals: MaybeUninit<[V; CAPACITY]>,
}
impl<K, V> LeafNode<K, V> {
LeafNode {
// As a general policy, we leave fields uninitialized if they can be, as this should
// be both slightly faster and easier to track in Valgrind.
- keys: mem::uninitialized(),
- vals: mem::uninitialized(),
+ keys: MaybeUninit::uninitialized(),
+ vals: MaybeUninit::uninitialized(),
parent: ptr::null(),
- parent_idx: mem::uninitialized(),
+ parent_idx: MaybeUninit::uninitialized(),
len: 0
}
}
// ever take a pointer past the first key.
static EMPTY_ROOT_NODE: LeafNode<(), ()> = LeafNode {
parent: ptr::null(),
- parent_idx: 0,
+ parent_idx: MaybeUninit::uninitialized(),
len: 0,
- keys: [(); CAPACITY],
- vals: [(); CAPACITY],
+ keys: MaybeUninit::uninitialized(),
+ vals: MaybeUninit::uninitialized(),
};
/// The underlying representation of internal nodes. As with `LeafNode`s, these should be hidden
root: self.root,
_marker: PhantomData
},
- idx: self.as_leaf().parent_idx as usize,
+ idx: unsafe { usize::from(*self.as_leaf().parent_idx.get_ref()) },
_marker: PhantomData
})
} else {
// the node, which is allowed by LLVM.
unsafe {
slice::from_raw_parts(
- self.as_leaf().keys.as_ptr(),
+ self.as_leaf().keys.as_ptr() as *const K,
self.len()
)
}
debug_assert!(!self.is_shared_root());
unsafe {
slice::from_raw_parts(
- self.as_leaf().vals.as_ptr(),
+ self.as_leaf().vals.as_ptr() as *const V,
self.len()
)
}
} else {
unsafe {
slice::from_raw_parts_mut(
- &mut self.as_leaf_mut().keys as *mut [K] as *mut K,
+ self.as_leaf_mut().keys.get_mut() as *mut [K] as *mut K,
self.len()
)
}
debug_assert!(!self.is_shared_root());
unsafe {
slice::from_raw_parts_mut(
- &mut self.as_leaf_mut().vals as *mut [V] as *mut V,
+ self.as_leaf_mut().vals.get_mut() as *mut [V] as *mut V,
self.len()
)
}
let ptr = self.node.as_internal_mut() as *mut _;
let mut child = self.descend();
child.as_leaf_mut().parent = ptr;
- child.as_leaf_mut().parent_idx = idx;
+ child.as_leaf_mut().parent_idx.set(idx);
}
/// Unsafely asserts to the compiler some static information about whether the underlying
ptr::copy_nonoverlapping(
self.node.keys().as_ptr().add(self.idx + 1),
- new_node.keys.as_mut_ptr(),
+ new_node.keys.as_mut_ptr() as *mut K,
new_len
);
ptr::copy_nonoverlapping(
self.node.vals().as_ptr().add(self.idx + 1),
- new_node.vals.as_mut_ptr(),
+ new_node.vals.as_mut_ptr() as *mut V,
new_len
);
ptr::copy_nonoverlapping(
self.node.keys().as_ptr().add(self.idx + 1),
- new_node.data.keys.as_mut_ptr(),
+ new_node.data.keys.as_mut_ptr() as *mut K,
new_len
);
ptr::copy_nonoverlapping(
self.node.vals().as_ptr().add(self.idx + 1),
- new_node.data.vals.as_mut_ptr(),
+ new_node.data.vals.as_mut_ptr() as *mut V,
new_len
);
ptr::copy_nonoverlapping(
#![feature(rustc_const_unstable)]
#![feature(const_vec_new)]
#![feature(slice_partition_dedup)]
+#![feature(maybe_uninit)]
// Allow testing this library
/// assert_eq!(vec, [1, 2, 3, 4]);
/// ```
///
-/// It can also initialize each element of a `Vec<T>` with a given value:
+/// It can also initialize each element of a `Vec<T>` with a given value.
+/// This may be more efficient than performing allocation and initialization
+/// in separate steps, especially when initializing a vector of zeros:
///
/// ```
/// let vec = vec![0; 5];
/// assert_eq!(vec, [0, 0, 0, 0, 0]);
+///
+/// // The following is equivalent, but potentially slower:
+/// let mut vec1 = Vec::with_capacity(5);
+/// vec1.resize(5, 0);
/// ```
///
/// Use a `Vec<T>` as an efficient stack:
///
/// Note, that this table does not contain values where inverse does not exist (i.e. for
/// `0⁻¹ mod 16`, `2⁻¹ mod 16`, etc.)
- const INV_TABLE_MOD_16: [usize; 8] = [1, 11, 13, 7, 9, 3, 5, 15];
+ const INV_TABLE_MOD_16: [u8; 8] = [1, 11, 13, 7, 9, 3, 5, 15];
/// Modulo for which the `INV_TABLE_MOD_16` is intended.
const INV_TABLE_MOD: usize = 16;
/// INV_TABLE_MOD²
const INV_TABLE_MOD_SQUARED: usize = INV_TABLE_MOD * INV_TABLE_MOD;
- let table_inverse = INV_TABLE_MOD_16[(x & (INV_TABLE_MOD - 1)) >> 1];
+ let table_inverse = INV_TABLE_MOD_16[(x & (INV_TABLE_MOD - 1)) >> 1] as usize;
if m <= INV_TABLE_MOD {
table_inverse & (m - 1)
} else {
let gcdpow = intrinsics::cttz_nonzero(stride).min(intrinsics::cttz_nonzero(a));
let gcd = 1usize << gcdpow;
- if gcd == 1 {
- // This branch solves for the variable $o$ in following linear congruence equation:
- //
- // ⎰ p + o ≡ 0 (mod a) # $p + o$ must be aligned to specified alignment $a$
- // ⎱ o ≡ 0 (mod s) # offset $o$ must be a multiple of stride $s$
- //
- // where
+ if p as usize & (gcd - 1) == 0 {
+ // This branch solves for the following linear congruence equation:
//
- // * a, s are co-prime
+ // $$ p + so ≡ 0 mod a $$
//
- // This gives us the formula below:
+ // $p$ here is the pointer value, $s$ – stride of `T`, $o$ offset in `T`s, and $a$ – the
+ // requested alignment.
//
- // o = (a - (p mod a)) * (s⁻¹ mod a) * s
+ // g = gcd(a, s)
+ // o = (a - (p mod a))/g * ((s/g)⁻¹ mod a)
//
// The first term is “the relative alignment of p to a”, the second term is “how does
- // incrementing p by one s change the relative alignment of p”, the third term is
- // translating change in units of s to a byte count.
+ // incrementing p by s bytes change the relative alignment of p”. Division by `g` is
+ // necessary to make this equation well formed if $a$ and $s$ are not co-prime.
//
// Furthermore, the result produced by this solution is not “minimal”, so it is necessary
- // to take the result $o mod lcm(s, a)$. Since $s$ and $a$ are co-prime (i.e. $gcd(s, a) =
- // 1$) and $lcm(s, a) = s * a / gcd(s, a)$, we can replace $lcm(s, a)$ with just a $s * a$.
- //
- // (Author note: we decided later on to express the offset in "elements" rather than bytes,
- // which drops the multiplication by `s` on both sides of the modulo.)
- return intrinsics::unchecked_rem(a.wrapping_sub(pmoda).wrapping_mul(mod_inv(smoda, a)), a);
- }
-
- if p as usize & (gcd - 1) == 0 {
- // This can be aligned, but `a` and `stride` are not co-prime, so a somewhat adapted
- // formula is used.
+ // to take the result $o mod lcm(s, a)$. We can replace $lcm(s, a)$ with just a $a / g$.
let j = a.wrapping_sub(pmoda) >> gcdpow;
let k = smoda >> gcdpow;
return intrinsics::unchecked_rem(j.wrapping_mul(mod_inv(k, a)), a >> gcdpow);
fn gcd(a: usize, b: usize) -> usize {
// iterative stein’s algorithm
// We should still make this `const fn` (and revert to recursive algorithm if we do)
- // because relying on llvm to consteval all this is… well, it makes me
+ // because relying on llvm to consteval all this is… well, it makes me uncomfortable.
let (ctz_a, mut ctz_b) = unsafe {
if a == 0 { return b; }
if b == 0 { return a; }
"output a json file with profiler results"),
emit_stack_sizes: bool = (false, parse_bool, [UNTRACKED],
"emits a section containing stack size metadata"),
+ plt: Option<bool> = (None, parse_opt_bool, [TRACKED],
+ "whether to use the PLT when calling into shared libraries;
+ only has effect for PIC code on systems with ELF binaries
+ (default: PLT is disabled if full relro is enabled)"),
}
pub fn default_lib_output() -> CrateType {
use syntax_pos::{MultiSpan, Span};
use util::profiling::SelfProfiler;
-use rustc_target::spec::PanicStrategy;
-use rustc_target::spec::{Target, TargetTriple};
+use rustc_target::spec::{PanicStrategy, RelroLevel, Target, TargetTriple};
use rustc_data_structures::flock;
use jobserver::Client;
pub fn edition(&self) -> Edition {
self.opts.edition
}
+
+ /// True if we cannot skip the PLT for shared library calls.
+ pub fn needs_plt(&self) -> bool {
+ // Check if the current target usually needs PLT to be enabled.
+ // The user can use the command line flag to override it.
+ let needs_plt = self.target.target.options.needs_plt;
+
+ let dbg_opts = &self.opts.debugging_opts;
+
+ let relro_level = dbg_opts.relro_level
+ .unwrap_or(self.target.target.options.relro_level);
+
+ // Only enable this optimization by default if full relro is also enabled.
+ // In this case, lazy binding was already unavailable, so nothing is lost.
+ // This also ensures `-Wl,-z,now` is supported by the linker.
+ let full_relro = RelroLevel::Full == relro_level;
+
+ // If user didn't explicitly forced us to use / skip the PLT,
+ // then try to skip it where possible.
+ dbg_opts.plt.unwrap_or(needs_plt || !full_relro)
+ }
}
pub fn build_session(
target_cpu.as_c_str());
}
+/// Sets the `NonLazyBind` LLVM attribute on a given function,
+/// assuming the codegen options allow skipping the PLT.
+pub fn non_lazy_bind(sess: &Session, llfn: &'ll Value) {
+ // Don't generate calls through PLT if it's not necessary
+ if !sess.needs_plt() {
+ Attribute::NonLazyBind.apply_llfn(Function, llfn);
+ }
+}
+
/// Composite function which sets LLVM attributes for function depending on its AST (#[attribute])
/// attributes.
pub fn from_fn_attrs(
llvm::LLVMRustSetModulePIELevel(llmod);
}
+ // If skipping the PLT is enabled, we need to add some module metadata
+ // to ensure intrinsic calls don't use it.
+ if !sess.needs_plt() {
+ let avoid_plt = "RtLibUseGOT\0".as_ptr() as *const _;
+ llvm::LLVMRustAddModuleFlag(llmod, avoid_plt, 1);
+ }
+
llmod
}
attributes::unwind(llfn, false);
}
+ attributes::non_lazy_bind(cx.sess(), llfn);
+
llfn
}
SanitizeThread = 20,
SanitizeAddress = 21,
SanitizeMemory = 22,
+ NonLazyBind = 23,
}
/// LLVMIntPredicate
enum BorrowedContentSource {
Arc,
Rc,
+ DerefRawPointer,
Other,
}
match *self {
BorrowedContentSource::Arc => write!(f, "an `Arc`"),
BorrowedContentSource::Rc => write!(f, "an `Rc`"),
+ BorrowedContentSource::DerefRawPointer => write!(f, "dereference of raw pointer"),
BorrowedContentSource::Other => write!(f, "borrowed content"),
}
}
self.prefixes(&original_path, PrefixSet::All)
.any(|p| p.is_upvar_field_projection(self.mir, &self.infcx.tcx)
.is_some());
+ debug!("report: ty={:?}", ty);
match ty.sty {
ty::Array(..) | ty::Slice(..) =>
self.infcx.tcx.cannot_move_out_of_interior_noncopy(
}
}
+ // If we didn't find an `Arc` or an `Rc`, then check specifically for
+ // a dereference of a place that has the type of a raw pointer.
+ // We can't use `place.ty(..).to_ty(..)` here as that strips away the raw pointer.
+ if let Place::Projection(box Projection {
+ base,
+ elem: ProjectionElem::Deref,
+ }) = place {
+ if base.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx).is_unsafe_ptr() {
+ return BorrowedContentSource::DerefRawPointer;
+ }
+ }
+
BorrowedContentSource::Other
}
}
/// the functions in the executable are not randomized and can be used
/// during an exploit of a vulnerability in any code.
pub position_independent_executables: bool,
+ /// Determines if the target always requires using the PLT for indirect
+ /// library calls or not. This controls the default value of the `-Z plt` flag.
+ pub needs_plt: bool,
/// Either partial, full, or off. Full RELRO makes the dynamic linker
/// resolve all symbols at startup and marks the GOT read-only before
/// starting the program, preventing overwriting the GOT.
has_rpath: false,
no_default_libraries: true,
position_independent_executables: false,
+ needs_plt: false,
relro_level: RelroLevel::None,
pre_link_objects_exe: Vec::new(),
pre_link_objects_exe_crt: Vec::new(),
key!(has_rpath, bool);
key!(no_default_libraries, bool);
key!(position_independent_executables, bool);
+ key!(needs_plt, bool);
try!(key!(relro_level, RelroLevel));
key!(archive_format);
key!(allow_asm, bool);
target_option_val!(has_rpath);
target_option_val!(no_default_libraries);
target_option_val!(position_independent_executables);
+ target_option_val!(needs_plt);
target_option_val!(relro_level);
target_option_val!(archive_format);
target_option_val!(allow_asm);
base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-mx32".to_string());
base.stack_probes = true;
base.has_elf_tls = false;
+ // BUG(GabrielMajeri): disabling the PLT on x86_64 Linux with x32 ABI
+ // breaks code gen. See LLVM bug 36743
+ base.needs_plt = true;
Ok(Target {
llvm_target: "x86_64-unknown-linux-gnux32".to_string(),
}
write_header(class, &mut out).unwrap();
- let mut classifier = Classifier::new(lexer::StringReader::new(&sess, fm, None),
- sess.source_map());
+ let lexer = match lexer::StringReader::new_without_err(&sess, fm, None, "Output from rustc:") {
+ Ok(l) => l,
+ Err(_) => {
+ let first_line = src.lines().next().unwrap_or_else(|| "");
+ let mut err = sess.span_diagnostic
+ .struct_warn(&format!("Invalid doc comment starting with: `{}`\n\
+ (Ignoring this codeblock)",
+ first_line));
+ err.emit();
+ return String::new();
+ }
+ };
+ let mut classifier = Classifier::new(lexer, sess.source_map());
if classifier.write_source(&mut out).is_err() {
+ classifier.lexer.emit_fatal_errors();
return format!("<pre>{}</pre>", src);
}
match self.lexer.try_next_token() {
Ok(tas) => Ok(tas),
Err(_) => {
- self.lexer.emit_fatal_errors();
- self.lexer.sess.span_diagnostic
- .struct_warn("Backing out of syntax highlighting")
- .note("You probably did not intend to render this as a rust code-block")
- .emit();
+ let mut err = self.lexer.sess.span_diagnostic
+ .struct_warn("Backing out of syntax highlighting");
+ err.note("You probably did not intend to render this as a rust code-block");
+ err.emit();
Err(io::Error::new(io::ErrorKind::Other, ""))
}
}
/// `&mut T` references can be freely coerced into `&T` references with the same referent type, and
/// references with longer lifetimes can be freely coerced into references with shorter ones.
///
+/// Reference equality by address, instead of comparing the values pointed to, is accomplished via
+/// implicit reference-pointer coercion and raw pointer equality via [`ptr::eq`], while
+/// [`PartialEq`] compares values.
+///
+/// [`ptr::eq`]: ptr/fn.eq.html
+/// [`PartialEq`]: cmp/trait.PartialEq.html
+///
+/// ```
+/// use std::ptr;
+///
+/// let five = 5;
+/// let other_five = 5;
+/// let five_ref = &five;
+/// let same_five_ref = &five;
+/// let other_five_ref = &other_five;
+///
+/// assert!(five_ref == same_five_ref);
+/// assert!(five_ref == other_five_ref);
+///
+/// assert!(ptr::eq(five_ref, same_five_ref));
+/// assert!(!ptr::eq(five_ref, other_five_ref));
+/// ```
+///
/// For more information on how to use references, see [the book's section on "References and
/// Borrowing"][book-refs].
///
/// [book-refs]: ../book/second-edition/ch04-02-references-and-borrowing.html
///
+/// # Trait implementations
+///
/// The following traits are implemented for all `&T`, regardless of the type of its referent:
///
/// * [`Copy`]
sr
}
+ pub fn new_without_err(sess: &'a ParseSess,
+ source_file: Lrc<syntax_pos::SourceFile>,
+ override_span: Option<Span>,
+ prepend_error_text: &str) -> Result<Self, ()> {
+ let mut sr = StringReader::new_raw(sess, source_file, override_span);
+ if sr.advance_token().is_err() {
+ eprintln!("{}", prepend_error_text);
+ sr.emit_fatal_errors();
+ return Err(());
+ }
+ Ok(sr)
+ }
+
pub fn retokenize(sess: &'a ParseSess, mut span: Span) -> Self {
let begin = sess.source_map().lookup_byte_offset(span.lo());
let end = sess.source_map().lookup_byte_offset(span.hi());
return Attribute::SanitizeAddress;
case SanitizeMemory:
return Attribute::SanitizeMemory;
+ case NonLazyBind:
+ return Attribute::NonLazyBind;
}
report_fatal_error("bad AttributeKind");
}
SanitizeThread = 20,
SanitizeAddress = 21,
SanitizeMemory = 22,
+ NonLazyBind = 23,
};
typedef struct OpaqueRustString *RustStringRef;
#![crate_type = "lib"]
#![feature(naked_functions)]
-// CHECK: Function Attrs: naked uwtable
+// CHECK: Function Attrs: naked
// CHECK-NEXT: define void @naked_empty()
#[no_mangle]
#[naked]
// CHECK-NEXT: ret void
}
-// CHECK: Function Attrs: naked uwtable
+// CHECK: Function Attrs: naked
#[no_mangle]
#[naked]
// CHECK-NEXT: define void @naked_with_args(i{{[0-9]+}})
// CHECK: ret void
}
-// CHECK: Function Attrs: naked uwtable
+// CHECK: Function Attrs: naked
// CHECK-NEXT: define i{{[0-9]+}} @naked_with_return()
#[no_mangle]
#[naked]
0
}
-// CHECK: Function Attrs: naked uwtable
+// CHECK: Function Attrs: naked
// CHECK-NEXT: define i{{[0-9]+}} @naked_with_args_and_return(i{{[0-9]+}})
#[no_mangle]
#[naked]
a
}
-// CHECK: Function Attrs: naked uwtable
+// CHECK: Function Attrs: naked
// CHECK-NEXT: define void @naked_recursive()
#[no_mangle]
#[naked]
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: -C relocation-model=pic -Z plt=no
+
+#![crate_type = "lib"]
+
+// We need a function which is normally called through the PLT.
+extern "C" {
+ // CHECK: Function Attrs: nounwind nonlazybind
+ fn getenv(name: *const u8) -> *mut u8;
+}
+
+// Ensure the function gets referenced.
+pub unsafe fn call_through_plt() -> *mut u8 {
+ getenv(b"\0".as_ptr())
+}
+
+// Ensure intrinsics also skip the PLT
+// CHECK: !"RtLibUseGOT"
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-pass
+// compile-flags: --error-format=human
+
+/// ```
+/// \__________pkt->size___________/ \_result->size_/ \__pkt->size__/
+/// ```
+pub fn foo() {}
--- /dev/null
+Output from rustc:
+error: unknown start of token: /
+ --> <stdin>:1:1
+ |
+1 | /__________pkt->size___________/ /_result->size_/ /__pkt->size__/
+ | ^
+
+warning: Invalid doc comment starting with: `/__________pkt->size___________/ /_result->size_/ /__pkt->size__/`
+(Ignoring this codeblock)
+
-error[E0507]: cannot move out of borrowed content
+error[E0507]: cannot move out of dereference of raw pointer
--> $DIR/borrowck-move-from-unsafe-ptr.rs:13:13
|
LL | let y = *x; //~ ERROR cannot move out of dereference of raw pointer
| ^^
| |
- | cannot move out of borrowed content
+ | cannot move out of dereference of raw pointer
| help: consider removing the `*`: `x`
error: aborting due to previous error
| cannot move out of borrowed content
| help: consider removing the `*`: `imm_ref()`
-error[E0507]: cannot move out of borrowed content
+error[E0507]: cannot move out of dereference of raw pointer
--> $DIR/issue-20801.rs:42:22
|
LL | let c = unsafe { *mut_ptr() };
| ^^^^^^^^^^
| |
- | cannot move out of borrowed content
+ | cannot move out of dereference of raw pointer
| help: consider removing the `*`: `mut_ptr()`
-error[E0507]: cannot move out of borrowed content
+error[E0507]: cannot move out of dereference of raw pointer
--> $DIR/issue-20801.rs:45:22
|
LL | let d = unsafe { *const_ptr() };
| ^^^^^^^^^^^^
| |
- | cannot move out of borrowed content
+ | cannot move out of dereference of raw pointer
| help: consider removing the `*`: `const_ptr()`
error: aborting due to 4 previous errors