Auto merge of #52474 - alexcrichton:better-lto-error, r=eddyb
rustc: Handle linker diagnostics from LLVM Previously linker diagnostic were being hidden when two modules were linked together but failed to link. This commit fixes the situation by ensuring that we have a diagnostic handler installed and also adds support for handling linker diagnostics.
This commit is contained in:
commit
11f812aa7d
@ -11,7 +11,7 @@
|
|||||||
use back::bytecode::{DecodedBytecode, RLIB_BYTECODE_EXTENSION};
|
use back::bytecode::{DecodedBytecode, RLIB_BYTECODE_EXTENSION};
|
||||||
use back::symbol_export;
|
use back::symbol_export;
|
||||||
use back::write::{ModuleConfig, with_llvm_pmb, CodegenContext};
|
use back::write::{ModuleConfig, with_llvm_pmb, CodegenContext};
|
||||||
use back::write;
|
use back::write::{self, DiagnosticHandlers};
|
||||||
use errors::{FatalError, Handler};
|
use errors::{FatalError, Handler};
|
||||||
use llvm::archive_ro::ArchiveRO;
|
use llvm::archive_ro::ArchiveRO;
|
||||||
use llvm::{True, False};
|
use llvm::{True, False};
|
||||||
@ -234,9 +234,17 @@ fn fat_lto(cgcx: &CodegenContext,
|
|||||||
let module = modules.remove(costliest_module);
|
let module = modules.remove(costliest_module);
|
||||||
let mut serialized_bitcode = Vec::new();
|
let mut serialized_bitcode = Vec::new();
|
||||||
{
|
{
|
||||||
let llmod = module.llvm().expect("can't lto pre-codegened modules").llmod();
|
let (llcx, llmod) = {
|
||||||
|
let llvm = module.llvm().expect("can't lto pre-codegened modules");
|
||||||
|
(&llvm.llcx, llvm.llmod())
|
||||||
|
};
|
||||||
info!("using {:?} as a base module", module.llmod_id);
|
info!("using {:?} as a base module", module.llmod_id);
|
||||||
|
|
||||||
|
// The linking steps below may produce errors and diagnostics within LLVM
|
||||||
|
// which we'd like to handle and print, so set up our diagnostic handlers
|
||||||
|
// (which get unregistered when they go out of scope below).
|
||||||
|
let _handler = DiagnosticHandlers::new(cgcx, diag_handler, llcx);
|
||||||
|
|
||||||
// For all other modules we codegened we'll need to link them into our own
|
// For all other modules we codegened we'll need to link them into our own
|
||||||
// bitcode. All modules were codegened in their own LLVM context, however,
|
// bitcode. All modules were codegened in their own LLVM context, however,
|
||||||
// and we want to move everything to the same LLVM context. Currently the
|
// and we want to move everything to the same LLVM context. Currently the
|
||||||
|
@ -397,15 +397,15 @@ pub(crate) fn save_temp_bitcode(&self, module: &ModuleCodegen, name: &str) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct DiagnosticHandlers<'a> {
|
pub struct DiagnosticHandlers<'a> {
|
||||||
data: *mut (&'a CodegenContext, &'a Handler),
|
data: *mut (&'a CodegenContext, &'a Handler),
|
||||||
llcx: &'a llvm::Context,
|
llcx: &'a llvm::Context,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> DiagnosticHandlers<'a> {
|
impl<'a> DiagnosticHandlers<'a> {
|
||||||
fn new(cgcx: &'a CodegenContext,
|
pub fn new(cgcx: &'a CodegenContext,
|
||||||
handler: &'a Handler,
|
handler: &'a Handler,
|
||||||
llcx: &'a llvm::Context) -> Self {
|
llcx: &'a llvm::Context) -> Self {
|
||||||
let data = Box::into_raw(Box::new((cgcx, handler)));
|
let data = Box::into_raw(Box::new((cgcx, handler)));
|
||||||
unsafe {
|
unsafe {
|
||||||
llvm::LLVMRustSetInlineAsmDiagnosticHandler(llcx, inline_asm_handler, data as *mut _);
|
llvm::LLVMRustSetInlineAsmDiagnosticHandler(llcx, inline_asm_handler, data as *mut _);
|
||||||
@ -475,10 +475,11 @@ fn drop(&mut self) {
|
|||||||
opt.message));
|
opt.message));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
llvm::diagnostic::PGO(diagnostic_ref) => {
|
llvm::diagnostic::PGO(diagnostic_ref) |
|
||||||
|
llvm::diagnostic::Linker(diagnostic_ref) => {
|
||||||
let msg = llvm::build_string(|s| {
|
let msg = llvm::build_string(|s| {
|
||||||
llvm::LLVMRustWriteDiagnosticInfoToString(diagnostic_ref, s)
|
llvm::LLVMRustWriteDiagnosticInfoToString(diagnostic_ref, s)
|
||||||
}).expect("non-UTF8 PGO diagnostic");
|
}).expect("non-UTF8 diagnostic");
|
||||||
diag_handler.warn(&msg);
|
diag_handler.warn(&msg);
|
||||||
}
|
}
|
||||||
llvm::diagnostic::UnknownDiagnostic(..) => {},
|
llvm::diagnostic::UnknownDiagnostic(..) => {},
|
||||||
|
@ -126,6 +126,7 @@ pub enum Diagnostic<'ll> {
|
|||||||
Optimization(OptimizationDiagnostic<'ll>),
|
Optimization(OptimizationDiagnostic<'ll>),
|
||||||
InlineAsm(InlineAsmDiagnostic<'ll>),
|
InlineAsm(InlineAsmDiagnostic<'ll>),
|
||||||
PGO(&'ll DiagnosticInfo),
|
PGO(&'ll DiagnosticInfo),
|
||||||
|
Linker(&'ll DiagnosticInfo),
|
||||||
|
|
||||||
/// LLVM has other types that we do not wrap here.
|
/// LLVM has other types that we do not wrap here.
|
||||||
UnknownDiagnostic(&'ll DiagnosticInfo),
|
UnknownDiagnostic(&'ll DiagnosticInfo),
|
||||||
@ -168,6 +169,9 @@ pub unsafe fn unpack(di: &'ll DiagnosticInfo) -> Self {
|
|||||||
Dk::PGOProfile => {
|
Dk::PGOProfile => {
|
||||||
PGO(di)
|
PGO(di)
|
||||||
}
|
}
|
||||||
|
Dk::Linker => {
|
||||||
|
Linker(di)
|
||||||
|
}
|
||||||
|
|
||||||
_ => UnknownDiagnostic(di),
|
_ => UnknownDiagnostic(di),
|
||||||
}
|
}
|
||||||
|
@ -332,6 +332,7 @@ pub enum DiagnosticKind {
|
|||||||
OptimizationRemarkOther,
|
OptimizationRemarkOther,
|
||||||
OptimizationFailure,
|
OptimizationFailure,
|
||||||
PGOProfile,
|
PGOProfile,
|
||||||
|
Linker,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// LLVMRustArchiveKind
|
/// LLVMRustArchiveKind
|
||||||
|
@ -984,6 +984,7 @@ enum class LLVMRustDiagnosticKind {
|
|||||||
OptimizationRemarkOther,
|
OptimizationRemarkOther,
|
||||||
OptimizationFailure,
|
OptimizationFailure,
|
||||||
PGOProfile,
|
PGOProfile,
|
||||||
|
Linker,
|
||||||
};
|
};
|
||||||
|
|
||||||
static LLVMRustDiagnosticKind toRust(DiagnosticKind Kind) {
|
static LLVMRustDiagnosticKind toRust(DiagnosticKind Kind) {
|
||||||
@ -1008,6 +1009,8 @@ static LLVMRustDiagnosticKind toRust(DiagnosticKind Kind) {
|
|||||||
return LLVMRustDiagnosticKind::OptimizationRemarkAnalysisAliasing;
|
return LLVMRustDiagnosticKind::OptimizationRemarkAnalysisAliasing;
|
||||||
case DK_PGOProfile:
|
case DK_PGOProfile:
|
||||||
return LLVMRustDiagnosticKind::PGOProfile;
|
return LLVMRustDiagnosticKind::PGOProfile;
|
||||||
|
case DK_Linker:
|
||||||
|
return LLVMRustDiagnosticKind::Linker;
|
||||||
default:
|
default:
|
||||||
return (Kind >= DK_FirstRemark && Kind <= DK_LastRemark)
|
return (Kind >= DK_FirstRemark && Kind <= DK_LastRemark)
|
||||||
? LLVMRustDiagnosticKind::OptimizationRemarkOther
|
? LLVMRustDiagnosticKind::OptimizationRemarkOther
|
||||||
|
16
src/test/compile-fail/auxiliary/lto-duplicate-symbols1.rs
Normal file
16
src/test/compile-fail/auxiliary/lto-duplicate-symbols1.rs
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
// no-prefer-dynamic
|
||||||
|
|
||||||
|
#![crate_type = "rlib"]
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern fn foo() {}
|
16
src/test/compile-fail/auxiliary/lto-duplicate-symbols2.rs
Normal file
16
src/test/compile-fail/auxiliary/lto-duplicate-symbols2.rs
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
// no-prefer-dynamic
|
||||||
|
|
||||||
|
#![crate_type = "rlib"]
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern fn foo() {}
|
20
src/test/compile-fail/lto-duplicate-symbols.rs
Normal file
20
src/test/compile-fail/lto-duplicate-symbols.rs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
// aux-build:lto-duplicate-symbols1.rs
|
||||||
|
// aux-build:lto-duplicate-symbols2.rs
|
||||||
|
// error-pattern:Linking globals named 'foo': symbol multiply defined!
|
||||||
|
// compile-flags: -C lto
|
||||||
|
// no-prefer-dynamic
|
||||||
|
|
||||||
|
extern crate lto_duplicate_symbols1;
|
||||||
|
extern crate lto_duplicate_symbols2;
|
||||||
|
|
||||||
|
fn main() {}
|
Loading…
Reference in New Issue
Block a user