Skip to content
14 changes: 13 additions & 1 deletion compiler/rustc_builtin_macros/src/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -987,6 +987,7 @@ fn report_invalid_references(
// Collect all the implicit positions:
let mut spans = Vec::new();
let mut num_placeholders = 0;
let mut has_white_space_only_missing_arg = false;
for piece in template {
let mut placeholder = None;
// `{arg:.*}`
Expand All @@ -1009,13 +1010,21 @@ fn report_invalid_references(
}
// `{}`
if let FormatArgsPiece::Placeholder(FormatPlaceholder {
argument: FormatArgPosition { kind: FormatArgPositionKind::Implicit, .. },
argument: FormatArgPosition { kind: FormatArgPositionKind::Implicit, index, .. },
span,
..
}) = piece
{
placeholder = *span;
num_placeholders += 1;
// Check whether there's any non-space whitespace in the placeholder. If so, we should emit a note suggesting an escaping `{`.
if index.is_err()
&& let Some(span) = span
&& let Ok(snippet) = ecx.source_map().span_to_snippet(*span)
&& snippet.chars().any(|c| c.is_whitespace() && c != ' ')
{
has_white_space_only_missing_arg = true;
}
}
// For `{:.*}`, we only push one span.
spans.extend(placeholder);
Expand Down Expand Up @@ -1071,6 +1080,9 @@ fn report_invalid_references(
if has_precision_star {
e.note("positional arguments are zero-based");
}
if has_white_space_only_missing_arg {
e.note("if you intended to print `{`, you can escape it with `{{`");
}
} else {
let mut indexes: Vec<_> = invalid_refs.iter().map(|&(index, _, _, _)| index).collect();
// Avoid `invalid reference to positional arguments 7 and 7 (there is 1 argument)`
Expand Down
29 changes: 18 additions & 11 deletions compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ use crate::debuginfo::metadata::{
file_metadata_from_def_id, type_di_node, unknown_file_metadata,
};
use crate::debuginfo::utils::{DIB, create_DIArray, get_namespace_for_item};
use crate::llvm;
use crate::llvm::debuginfo::{DIFlags, DIType};
use crate::llvm::{self, ToLlvmBool};

mod cpp_like;
mod native;
Expand Down Expand Up @@ -111,16 +111,23 @@ fn build_enumeration_type_di_node<'ll, 'tcx>(
let (size, align) = cx.size_and_align_of(base_type);

let enumerator_di_nodes: SmallVec<Option<&'ll DIType>> = enumerators
.map(|(name, value)| unsafe {
let value = [value as u64, (value >> 64) as u64];
Some(llvm::LLVMRustDIBuilderCreateEnumerator(
DIB(cx),
name.as_c_char_ptr(),
name.len(),
value.as_ptr(),
size.bits() as libc::c_uint,
is_unsigned,
))
.map(|(name, value)| {
let value_words = [value as u64, (value >> 64) as u64];
let size_in_bits = size.bits();
// LLVM computes `NumWords = (SizeInBits + 63) / 64`.
assert!((size_in_bits + 63) / 64 <= value_words.len() as u64);

let enumerator = unsafe {
llvm::LLVMDIBuilderCreateEnumeratorOfArbitraryPrecision(
DIB(cx),
name.as_ptr(),
name.len(),
size_in_bits,
value_words.as_ptr(),
is_unsigned.to_llvm_bool(),
)
};
Some(enumerator)
})
.collect();

Expand Down
45 changes: 32 additions & 13 deletions compiler/rustc_codegen_llvm/src/llvm/ffi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,8 @@ use libc::{c_char, c_int, c_uchar, c_uint, c_ulonglong, c_void, size_t};

use super::RustString;
use super::debuginfo::{
DIArray, DIBuilder, DIDerivedType, DIDescriptor, DIEnumerator, DIFile, DIFlags, DILocation,
DISPFlags, DIScope, DISubprogram, DITemplateTypeParameter, DIType, DebugEmissionKind,
DebugNameTableKind,
DIArray, DIBuilder, DIDerivedType, DIDescriptor, DIFile, DIFlags, DILocation, DISPFlags,
DIScope, DISubprogram, DITemplateTypeParameter, DIType, DebugEmissionKind, DebugNameTableKind,
};
use crate::llvm::MetadataKindId;
use crate::{TryFromU32, llvm};
Expand Down Expand Up @@ -752,7 +751,6 @@ pub(crate) mod debuginfo {
pub(crate) type DICompositeType = DIDerivedType;
pub(crate) type DIVariable = DIDescriptor;
pub(crate) type DIArray = DIDescriptor;
pub(crate) type DIEnumerator = DIDescriptor;
pub(crate) type DITemplateTypeParameter = DIDescriptor;

bitflags! {
Expand Down Expand Up @@ -1794,6 +1792,15 @@ unsafe extern "C" {
Flags: DIFlags, // (default is `DIFlags::DIFlagZero`)
) -> &'ll Metadata;

pub(crate) fn LLVMDIBuilderCreateEnumeratorOfArbitraryPrecision<'ll>(
Builder: &DIBuilder<'ll>,
Name: *const c_uchar, // See "PTR_LEN_STR".
NameLen: size_t,
SizeInBits: u64,
Words: *const u64, // LLVM computes `NumWords = (SizeInBits + 63) / 64`.
IsUnsigned: llvm::Bool,
) -> &'ll Metadata;

pub(crate) fn LLVMDIBuilderCreateUnionType<'ll>(
Builder: &DIBuilder<'ll>,
Scope: Option<&'ll Metadata>,
Expand Down Expand Up @@ -1989,6 +1996,7 @@ unsafe extern "C" {
pub(crate) fn LLVMRustDisableSystemDialogsOnCrash();

// Operations on all values
/// FIXME: After dropping LLVM 21, migrate to LLVM-C's `LLVMGlobalAddMetadata`.
pub(crate) fn LLVMRustGlobalAddMetadata<'a>(
Val: &'a Value,
KindID: MetadataKindId,
Expand Down Expand Up @@ -2058,6 +2066,7 @@ unsafe extern "C" {
) -> &Attribute;

// Operations on functions
/// FIXME: After dropping LLVM 21, migrate to LLVM-C's `LLVMGetOrInsertFunction`.
pub(crate) fn LLVMRustGetOrInsertFunction<'a>(
M: &'a Module,
Name: *const c_char,
Expand Down Expand Up @@ -2208,6 +2217,9 @@ unsafe extern "C" {
ValueLen: size_t,
);

/// We can't use LLVM-C's `LLVMDIBuilderCreateCompileUnit` because it hardcodes
/// `DICompileUnit::DebugNameTableKind::Default`, but we want to be able to
/// pass other values.
pub(crate) fn LLVMRustDIBuilderCreateCompileUnit<'a>(
Builder: &DIBuilder<'a>,
Lang: c_uint,
Expand All @@ -2225,6 +2237,8 @@ unsafe extern "C" {
DebugNameTableKind: DebugNameTableKind,
) -> &'a DIDescriptor;

/// We can't use LLVM-C's `LLVMDIBuilderCreateFileWithChecksum` because it
/// _requires_ a checksum, but we sometimes don't provide one.
pub(crate) fn LLVMRustDIBuilderCreateFile<'a>(
Builder: &DIBuilder<'a>,
Filename: *const c_char,
Expand All @@ -2238,6 +2252,8 @@ unsafe extern "C" {
SourceLen: size_t,
) -> &'a DIFile;

/// We can't use LLVM-C's `LLVMDIBuilderCreateFunction` because it only
/// supports a subset of `DISubprogram::DISPFlags`.
pub(crate) fn LLVMRustDIBuilderCreateFunction<'a>(
Builder: &DIBuilder<'a>,
Scope: &'a DIDescriptor,
Expand All @@ -2256,6 +2272,7 @@ unsafe extern "C" {
Decl: Option<&'a DIDescriptor>,
) -> &'a DISubprogram;

/// As of LLVM 22 there is no corresponding LLVM-C function.
pub(crate) fn LLVMRustDIBuilderCreateMethod<'a>(
Builder: &DIBuilder<'a>,
Scope: &'a DIDescriptor,
Expand All @@ -2271,6 +2288,7 @@ unsafe extern "C" {
TParam: &'a DIArray,
) -> &'a DISubprogram;

/// As of LLVM 22 there is no corresponding LLVM-C function.
pub(crate) fn LLVMRustDIBuilderCreateVariantMemberType<'a>(
Builder: &DIBuilder<'a>,
Scope: &'a DIScope,
Expand All @@ -2286,15 +2304,7 @@ unsafe extern "C" {
Ty: &'a DIType,
) -> &'a DIType;

pub(crate) fn LLVMRustDIBuilderCreateEnumerator<'a>(
Builder: &DIBuilder<'a>,
Name: *const c_char,
NameLen: size_t,
Value: *const u64,
SizeInBits: c_uint,
IsUnsigned: bool,
) -> &'a DIEnumerator;

/// As of LLVM 22 there is no corresponding LLVM-C function.
pub(crate) fn LLVMRustDIBuilderCreateEnumerationType<'a>(
Builder: &DIBuilder<'a>,
Scope: &'a DIScope,
Expand All @@ -2309,6 +2319,7 @@ unsafe extern "C" {
IsScoped: bool,
) -> &'a DIType;

/// As of LLVM 22 there is no corresponding LLVM-C function.
pub(crate) fn LLVMRustDIBuilderCreateVariantPart<'a>(
Builder: &DIBuilder<'a>,
Scope: &'a DIScope,
Expand All @@ -2325,6 +2336,7 @@ unsafe extern "C" {
UniqueIdLen: size_t,
) -> &'a DIDerivedType;

/// As of LLVM 22 there is no corresponding LLVM-C function.
pub(crate) fn LLVMRustDIBuilderCreateTemplateTypeParameter<'a>(
Builder: &DIBuilder<'a>,
Scope: Option<&'a DIScope>,
Expand All @@ -2333,13 +2345,17 @@ unsafe extern "C" {
Ty: &'a DIType,
) -> &'a DITemplateTypeParameter;

/// We can't use LLVM-C's `LLVMReplaceArrays` because it doesn't take a
/// `Params` argument.
pub(crate) fn LLVMRustDICompositeTypeReplaceArrays<'a>(
Builder: &DIBuilder<'a>,
CompositeType: &'a DIType,
Elements: Option<&'a DIArray>,
Params: Option<&'a DIArray>,
);

/// We can't use LLVM-C's `LLVMDIBuilderGetOrCreateSubrange` because it doesn't
/// call the overload that takes a `Metadata` upper bound.
pub(crate) fn LLVMRustDIGetOrCreateSubrange<'a>(
Builder: &DIBuilder<'a>,
CountNode: Option<&'a Metadata>,
Expand All @@ -2348,6 +2364,8 @@ unsafe extern "C" {
Stride: Option<&'a Metadata>,
) -> &'a Metadata;

/// We can't use LLVM-C's `LLVMDIBuilderCreateVectorType` because it doesn't
/// take a `BitStride` argument.
pub(crate) fn LLVMRustDICreateVectorType<'a>(
Builder: &DIBuilder<'a>,
Size: u64,
Expand All @@ -2357,6 +2375,7 @@ unsafe extern "C" {
BitStride: Option<&'a Metadata>,
) -> &'a Metadata;

/// As of LLVM 22 there is no corresponding LLVM-C function.
pub(crate) fn LLVMRustDILocationCloneWithBaseDiscriminator<'a>(
Location: &'a DILocation,
BD: c_uint,
Expand Down
7 changes: 4 additions & 3 deletions compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer;
use rustc_hir_analysis::suggest_impl_trait;
use rustc_middle::middle::stability::EvalResult;
use rustc_middle::span_bug;
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::print::{with_no_trimmed_paths, with_types_for_suggestion};
use rustc_middle::ty::{
self, Article, Binder, IsSuggestable, Ty, TyCtxt, TypeVisitableExt, Unnormalized, Upcast,
suggest_constraining_type_params,
Expand Down Expand Up @@ -2679,8 +2679,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {

let sole_field_ty = sole_field.ty(self.tcx, args).skip_norm_wip();
if self.may_coerce(expr_ty, sole_field_ty) {
let variant_path =
with_no_trimmed_paths!(self.tcx.def_path_str(variant.def_id));
let variant_path = with_types_for_suggestion!(with_no_trimmed_paths!(
self.tcx.def_path_str(variant.def_id)
));
// FIXME #56861: DRYer prelude filtering
if let Some(path) = variant_path.strip_prefix("std::prelude::")
&& let Some((_, path)) = path.split_once("::")
Expand Down
9 changes: 0 additions & 9 deletions compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1198,15 +1198,6 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateVariantMemberType(
fromRust(Flags), unwrapDI<DIType>(Ty)));
}

extern "C" LLVMMetadataRef
LLVMRustDIBuilderCreateEnumerator(LLVMDIBuilderRef Builder, const char *Name,
size_t NameLen, const uint64_t Value[2],
unsigned SizeInBits, bool IsUnsigned) {
return wrap(unwrap(Builder)->createEnumerator(
StringRef(Name, NameLen),
APSInt(APInt(SizeInBits, ArrayRef<uint64_t>(Value, 2)), IsUnsigned)));
}

extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateEnumerationType(
LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name,
size_t NameLen, LLVMMetadataRef File, unsigned LineNumber,
Expand Down
11 changes: 11 additions & 0 deletions tests/ui/fmt/format-string-error-2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,4 +91,15 @@ raw { \n

println!("{x=}");
//~^ ERROR invalid format string: python's f-string debug `=` is not supported in rust, use `dbg(x)` instead

println!(
"fn main() {\n\
\n\
}"
//~^^^ ERROR 1 positional argument in format string
);

// Don't emit note suggesting an escaping `{` for `{ }`.
println!("{ }");
//~^ ERROR 1 positional argument in format string
}
19 changes: 18 additions & 1 deletion tests/ui/fmt/format-string-error-2.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -208,5 +208,22 @@ LL | println!("{x=}");
|
= note: to print `{`, you can escape it using `{{`

error: aborting due to 21 previous errors
error: 1 positional argument in format string, but no arguments were given
--> $DIR/format-string-error-2.rs:96:20
|
LL | "fn main() {\n\
| ____________________^
LL | | \n\
LL | | }"
| |_________^
|
= note: if you intended to print `{`, you can escape it with `{{`

error: 1 positional argument in format string, but no arguments were given
--> $DIR/format-string-error-2.rs:103:15
|
LL | println!("{ }");
| ^^^

error: aborting due to 23 previous errors

63 changes: 63 additions & 0 deletions tests/ui/suggestions/wrap-function-local-constructors.fixed
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
//@ run-rustfix

// Regression test for https://github.com/rust-lang/rust/issues/144319.
// Function-local constructors cannot be named through the enclosing function
// path. The suggestion must omit path segments that cannot be written in source,
// while preserving real path segments like local modules and enums.

#![allow(dead_code)]

fn direct_tuple_struct() {
struct Foo(bool);
struct Bar(Foo);

_ = Bar(Foo(false));
//~^ ERROR mismatched types
//~| HELP try wrapping the expression in `Foo`
}

fn enum_variant() {
enum LocalResult<T> {
Ok(T),
}
struct Bar(LocalResult<bool>);

_ = Bar(LocalResult::Ok(false));
//~^ ERROR mismatched types
//~| HELP try wrapping the expression in `LocalResult::Ok`
}

fn local_module() {
mod inner {
pub struct Foo(pub bool);
}
struct Bar(inner::Foo);

_ = Bar(inner::Foo(false));
//~^ ERROR mismatched types
//~| HELP try wrapping the expression in `inner::Foo`
}

fn closure_body() {
let _ = || {
struct Foo(bool);
struct Bar(Foo);

_ = Bar(Foo(false));
//~^ ERROR mismatched types
//~| HELP try wrapping the expression in `Foo`
};
}

fn inline_const_block() {
const {
struct Foo(bool);
struct Bar(Foo);

_ = Bar(Foo(false));
//~^ ERROR mismatched types
//~| HELP try wrapping the expression in `Foo`
};
}

pub fn main() {}
Loading
Loading