Skip to content

Commit 5e28561

Browse files
committedMar 19, 2020
Properly handle Spans that reference imported SourceFiles
Previously, metadata encoding used DUMMY_SP to represent any spans that referenced an 'imported' SourceFile - e.g. a SourceFile from an upstream dependency. These leads to sub-optimal error messages in certain cases (see the included test). This PR changes how we encode and decode spans in crate metadata. We encode spans in one of two ways: * 'Local' spans, which reference non-imported SourceFiles, are encoded exactly as before. * 'Foreign' spans, which reference imported SourceFiles, are encoded with the CrateNum of their 'originating' crate. Additionally, their 'lo' and 'high' values are rebased on top of the 'originating' crate, which allows them to be used with the SourceMap data encoded for that crate. The `ExternalSource` enum is renamed to `ExternalSourceKind`. There is now a struct called `ExternalSource`, which holds an `ExternalSourceKind` along with the original line number information for the file. This is used during `Span` serialization to rebase spans onto their 'owning' crate.
1 parent 57e1da5 commit 5e28561

File tree

11 files changed

+234
-52
lines changed

11 files changed

+234
-52
lines changed
 

‎src/librustc/hir/map/collector.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
1010
use rustc_data_structures::svh::Svh;
1111
use rustc_hir as hir;
1212
use rustc_hir::def_id::CRATE_DEF_INDEX;
13-
use rustc_hir::def_id::{CrateNum, DefIndex, LOCAL_CRATE};
13+
use rustc_hir::def_id::{DefIndex, LOCAL_CRATE};
1414
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
1515
use rustc_hir::*;
1616
use rustc_index::vec::{Idx, IndexVec};
@@ -175,7 +175,7 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> {
175175
.source_map
176176
.files()
177177
.iter()
178-
.filter(|source_file| CrateNum::from_u32(source_file.crate_of_origin) == LOCAL_CRATE)
178+
.filter(|source_file| source_file.cnum == LOCAL_CRATE)
179179
.map(|source_file| source_file.name_hash)
180180
.collect();
181181

‎src/librustc/ich/impls_syntax.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ use crate::ich::StableHashingContext;
55

66
use rustc_ast::ast;
77
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
8-
use rustc_hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX};
98
use rustc_span::SourceFile;
109

1110
use smallvec::SmallVec;
@@ -59,7 +58,7 @@ impl<'a> HashStable<StableHashingContext<'a>> for SourceFile {
5958
name_hash,
6059
name_was_remapped,
6160
unmapped_path: _,
62-
crate_of_origin,
61+
cnum,
6362
// Do not hash the source as it is not encoded
6463
src: _,
6564
src_hash,
@@ -75,9 +74,6 @@ impl<'a> HashStable<StableHashingContext<'a>> for SourceFile {
7574
(name_hash as u64).hash_stable(hcx, hasher);
7675
name_was_remapped.hash_stable(hcx, hasher);
7776

78-
DefId { krate: CrateNum::from_u32(crate_of_origin), index: CRATE_DEF_INDEX }
79-
.hash_stable(hcx, hasher);
80-
8177
src_hash.hash_stable(hcx, hasher);
8278

8379
// We only hash the relative position within this source_file
@@ -101,6 +97,8 @@ impl<'a> HashStable<StableHashingContext<'a>> for SourceFile {
10197
for &char_pos in normalized_pos.iter() {
10298
stable_normalized_pos(char_pos, start_pos).hash_stable(hcx, hasher);
10399
}
100+
101+
cnum.hash_stable(hcx, hasher);
104102
}
105103
}
106104

‎src/librustc_metadata/rmeta/decoder.rs

Lines changed: 85 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -386,7 +386,7 @@ impl<'a, 'tcx> SpecializedDecoder<Span> for DecodeContext<'a, 'tcx> {
386386
return Ok(DUMMY_SP);
387387
}
388388

389-
debug_assert_eq!(tag, TAG_VALID_SPAN);
389+
debug_assert!(tag == TAG_VALID_SPAN_LOCAL || tag == TAG_VALID_SPAN_FOREIGN);
390390

391391
let lo = BytePos::decode(self)?;
392392
let len = BytePos::decode(self)?;
@@ -398,7 +398,68 @@ impl<'a, 'tcx> SpecializedDecoder<Span> for DecodeContext<'a, 'tcx> {
398398
bug!("Cannot decode Span without Session.")
399399
};
400400

401-
let imported_source_files = self.cdata().imported_source_files(&sess.source_map());
401+
// There are two possibilities here:
402+
// 1. This is a 'local span', which is located inside a `SourceFile`
403+
// that came from this crate. In this case, we use the source map data
404+
// encoded in this crate. This branch should be taken nearly all of the time.
405+
// 2. This is a 'foreign span', which is located inside a `SourceFile`
406+
// that came from a *different* crate (some crate upstream of the one
407+
// whose metadata we're looking at). For example, consider this dependency graph:
408+
//
409+
// A -> B -> C
410+
//
411+
// Suppose that we're currently compiling crate A, and start deserializing
412+
// metadata from crate B. When we deserialize a Span from crate B's metadata,
413+
// there are two posibilites:
414+
//
415+
// 1. The span references a file from crate B. This makes it a 'local' span,
416+
// which means that we can use crate B's serialized source map information.
417+
// 2. The span references a file from crate C. This makes it a 'foreign' span,
418+
// which means we need to use Crate *C* (not crate B) to determine the source
419+
// map information. We only record source map information for a file in the
420+
// crate that 'owns' it, so deserializing a Span may require us to look at
421+
// a transitive dependency.
422+
//
423+
// When we encode a foreign span, we adjust its 'lo' and 'high' values
424+
// to be based on the *foreign* crate (e.g. crate C), not the crate
425+
// we are writing metadata for (e.g. crate B). This allows us to
426+
// treat the 'local' and 'foreign' cases almost identically during deserialization:
427+
// we can call `imported_source_files` for the proper crate, and binary search
428+
// through the returned slice using our span.
429+
let imported_source_files = if tag == TAG_VALID_SPAN_LOCAL {
430+
self.cdata().imported_source_files(sess.source_map())
431+
} else {
432+
// FIXME: We don't decode dependencies of proc-macros.
433+
// Remove this once #69976 is merged
434+
if self.cdata().root.is_proc_macro_crate() {
435+
debug!(
436+
"SpecializedDecoder<Span>::specialized_decode: skipping span for proc-macro crate {:?}",
437+
self.cdata().cnum
438+
);
439+
// Decode `CrateNum` as u32 - using `CrateNum::decode` will ICE
440+
// since we don't have `cnum_map` populated.
441+
// This advances the decoder position so that we can continue
442+
// to read metadata.
443+
let _ = u32::decode(self)?;
444+
return Ok(DUMMY_SP);
445+
}
446+
// tag is TAG_VALID_SPAN_FOREIGN, checked by `debug_assert` above
447+
let cnum = CrateNum::decode(self)?;
448+
debug!(
449+
"SpecializedDecoder<Span>::specialized_decode: loading source files from cnum {:?}",
450+
cnum
451+
);
452+
453+
// Decoding 'foreign' spans should be rare enough that it's
454+
// not worth it to maintain a per-CrateNum cache for `last_source_file_index`.
455+
// We just set it to 0, to ensure that we don't try to access something out
456+
// of bounds for our initial 'guess'
457+
self.last_source_file_index = 0;
458+
459+
let foreign_data = self.cdata().cstore.get_crate_data(cnum);
460+
foreign_data.imported_source_files(sess.source_map())
461+
};
462+
402463
let source_file = {
403464
// Optimize for the case that most spans within a translated item
404465
// originate from the same source_file.
@@ -412,16 +473,32 @@ impl<'a, 'tcx> SpecializedDecoder<Span> for DecodeContext<'a, 'tcx> {
412473
.binary_search_by_key(&lo, |source_file| source_file.original_start_pos)
413474
.unwrap_or_else(|index| index - 1);
414475

415-
self.last_source_file_index = index;
476+
// Don't try to cache the index for foreign spans,
477+
// as this would require a map from CrateNums to indices
478+
if tag == TAG_VALID_SPAN_LOCAL {
479+
self.last_source_file_index = index;
480+
}
416481
&imported_source_files[index]
417482
}
418483
};
419484

420485
// Make sure our binary search above is correct.
421-
debug_assert!(lo >= source_file.original_start_pos && lo <= source_file.original_end_pos);
486+
debug_assert!(
487+
lo >= source_file.original_start_pos && lo <= source_file.original_end_pos,
488+
"Bad binary search: lo={:?} source_file.original_start_pos={:?} source_file.original_end_pos={:?}",
489+
lo,
490+
source_file.original_start_pos,
491+
source_file.original_end_pos
492+
);
422493

423494
// Make sure we correctly filtered out invalid spans during encoding
424-
debug_assert!(hi >= source_file.original_start_pos && hi <= source_file.original_end_pos);
495+
debug_assert!(
496+
hi >= source_file.original_start_pos && hi <= source_file.original_end_pos,
497+
"Bad binary search: hi={:?} source_file.original_start_pos={:?} source_file.original_end_pos={:?}",
498+
hi,
499+
source_file.original_start_pos,
500+
source_file.original_end_pos
501+
);
425502

426503
let lo =
427504
(lo + source_file.translated_source_file.start_pos) - source_file.original_start_pos;
@@ -1425,14 +1502,16 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
14251502
let local_version = local_source_map.new_imported_source_file(
14261503
name,
14271504
name_was_remapped,
1428-
self.cnum.as_u32(),
14291505
src_hash,
14301506
name_hash,
14311507
source_length,
1508+
self.cnum,
14321509
lines,
14331510
multibyte_chars,
14341511
non_narrow_chars,
14351512
normalized_pos,
1513+
start_pos,
1514+
end_pos,
14361515
);
14371516
debug!(
14381517
"CrateMetaData::imported_source_files alloc \

‎src/librustc_metadata/rmeta/encoder.rs

Lines changed: 48 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use crate::rmeta::table::FixedSizeEncoding;
22
use crate::rmeta::*;
33

4+
use log::{debug, trace};
45
use rustc::hir::map::definitions::DefPathTable;
56
use rustc::hir::map::Map;
67
use rustc::middle::cstore::{EncodedMetadata, ForeignModule, LinkagePreference, NativeLibrary};
@@ -29,9 +30,7 @@ use rustc_serialize::{opaque, Encodable, Encoder, SpecializedEncoder};
2930
use rustc_session::config::{self, CrateType};
3031
use rustc_span::source_map::Spanned;
3132
use rustc_span::symbol::{kw, sym, Ident, Symbol};
32-
use rustc_span::{self, FileName, SourceFile, Span};
33-
34-
use log::{debug, trace};
33+
use rustc_span::{self, ExternalSource, FileName, SourceFile, Span};
3534
use std::hash::Hash;
3635
use std::num::NonZeroUsize;
3736
use std::path::Path;
@@ -165,20 +164,56 @@ impl<'tcx> SpecializedEncoder<Span> for EncodeContext<'tcx> {
165164
return TAG_INVALID_SPAN.encode(self);
166165
}
167166

168-
// HACK(eddyb) there's no way to indicate which crate a Span is coming
169-
// from right now, so decoding would fail to find the SourceFile if
170-
// it's not local to the crate the Span is found in.
171-
if self.source_file_cache.is_imported() {
172-
return TAG_INVALID_SPAN.encode(self);
173-
}
167+
// There are two possible cases here:
168+
// 1. This span comes from a 'foreign' crate - e.g. some crate upstream of the
169+
// crate we are writing metadata for. When the metadata for *this* crate gets
170+
// deserialized, the deserializer will need to know which crate it originally came
171+
// from. We use `TAG_VALID_SPAN_FOREIGN` to indicate that a `CrateNum` should
172+
// be deserialized after the rest of the span data, which tells the deserializer
173+
// which crate contains the source map information.
174+
// 2. This span comes from our own crate. No special hamdling is needed - we just
175+
// write `TAG_VALID_SPAN_LOCAL` to let the deserializer know that it should use
176+
// our own source map information.
177+
let (tag, lo, hi) = if self.source_file_cache.is_imported() {
178+
// To simplify deserialization, we 'rebase' this span onto the crate it originally came from
179+
// (the crate that 'owns' the file it references. These rebased 'lo' and 'hi' values
180+
// are relative to the source map information for the 'foreign' crate whose CrateNum
181+
// we write into the metadata. This allows `imported_source_files` to binary
182+
// search through the 'foreign' crate's source map information, using the
183+
// deserialized 'lo' and 'hi' values directly.
184+
//
185+
// All of this logic ensures that the final result of deserialization is a 'normal'
186+
// Span that can be used without any additional trouble.
187+
let external_start_pos = {
188+
// Introduce a new scope so that we drop the 'lock()' temporary
189+
match &*self.source_file_cache.external_src.lock() {
190+
ExternalSource::Foreign { original_start_pos, .. } => *original_start_pos,
191+
src => panic!("Unexpected external source {:?}", src),
192+
}
193+
};
194+
let lo = (span.lo - self.source_file_cache.start_pos) + external_start_pos;
195+
let hi = (span.hi - self.source_file_cache.start_pos) + external_start_pos;
174196

175-
TAG_VALID_SPAN.encode(self)?;
176-
span.lo.encode(self)?;
197+
(TAG_VALID_SPAN_FOREIGN, lo, hi)
198+
} else {
199+
(TAG_VALID_SPAN_LOCAL, span.lo, span.hi)
200+
};
201+
202+
tag.encode(self)?;
203+
lo.encode(self)?;
177204

178205
// Encode length which is usually less than span.hi and profits more
179206
// from the variable-length integer encoding that we use.
180-
let len = span.hi - span.lo;
181-
len.encode(self)
207+
let len = hi - lo;
208+
len.encode(self)?;
209+
210+
if tag == TAG_VALID_SPAN_FOREIGN {
211+
// This needs to be two lines to avoid holding the `self.source_file_cache`
212+
// while calling `cnum.encode(self)`
213+
let cnum = self.source_file_cache.cnum;
214+
cnum.encode(self)?;
215+
}
216+
Ok(())
182217

183218
// Don't encode the expansion context.
184219
}

‎src/librustc_metadata/rmeta/mod.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -405,5 +405,6 @@ struct GeneratorData<'tcx> {
405405
}
406406

407407
// Tags used for encoding Spans:
408-
const TAG_VALID_SPAN: u8 = 0;
409-
const TAG_INVALID_SPAN: u8 = 1;
408+
const TAG_VALID_SPAN_LOCAL: u8 = 0;
409+
const TAG_VALID_SPAN_FOREIGN: u8 = 1;
410+
const TAG_INVALID_SPAN: u8 = 2;

‎src/librustc_span/lib.rs

Lines changed: 40 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ pub mod hygiene;
2727
use hygiene::Transparency;
2828
pub use hygiene::{DesugaringKind, ExpnData, ExpnId, ExpnKind, MacroKind, SyntaxContext};
2929
pub mod def_id;
30-
use def_id::DefId;
30+
use def_id::{CrateNum, DefId, LOCAL_CRATE};
3131
mod span_encoding;
3232
pub use span_encoding::{Span, DUMMY_SP};
3333

@@ -839,30 +839,42 @@ pub struct NormalizedPos {
839839
pub diff: u32,
840840
}
841841

842-
/// The state of the lazy external source loading mechanism of a `SourceFile`.
843-
#[derive(PartialEq, Eq, Clone)]
842+
#[derive(PartialEq, Eq, Clone, Debug)]
844843
pub enum ExternalSource {
844+
/// No external source has to be loaded, since the `SourceFile` represents a local crate.
845+
Unneeded,
846+
Foreign {
847+
kind: ExternalSourceKind,
848+
/// This SourceFile's byte-offset within the source_map of its original crate
849+
original_start_pos: BytePos,
850+
/// The end of this SourceFile within the source_map of its original crate
851+
original_end_pos: BytePos,
852+
},
853+
}
854+
855+
/// The state of the lazy external source loading mechanism of a `SourceFile`.
856+
#[derive(PartialEq, Eq, Clone, Debug)]
857+
pub enum ExternalSourceKind {
845858
/// The external source has been loaded already.
846859
Present(String),
847860
/// No attempt has been made to load the external source.
848861
AbsentOk,
849862
/// A failed attempt has been made to load the external source.
850863
AbsentErr,
851-
/// No external source has to be loaded, since the `SourceFile` represents a local crate.
852864
Unneeded,
853865
}
854866

855867
impl ExternalSource {
856868
pub fn is_absent(&self) -> bool {
857-
match *self {
858-
ExternalSource::Present(_) => false,
869+
match self {
870+
ExternalSource::Foreign { kind: ExternalSourceKind::Present(_), .. } => false,
859871
_ => true,
860872
}
861873
}
862874

863875
pub fn get_source(&self) -> Option<&str> {
864-
match *self {
865-
ExternalSource::Present(ref src) => Some(src),
876+
match self {
877+
ExternalSource::Foreign { kind: ExternalSourceKind::Present(ref src), .. } => Some(src),
866878
_ => None,
867879
}
868880
}
@@ -883,8 +895,6 @@ pub struct SourceFile {
883895
/// The unmapped path of the file that the source came from.
884896
/// Set to `None` if the `SourceFile` was imported from an external crate.
885897
pub unmapped_path: Option<FileName>,
886-
/// Indicates which crate this `SourceFile` was imported from.
887-
pub crate_of_origin: u32,
888898
/// The complete source code.
889899
pub src: Option<Lrc<String>>,
890900
/// The source code's hash.
@@ -906,6 +916,8 @@ pub struct SourceFile {
906916
pub normalized_pos: Vec<NormalizedPos>,
907917
/// A hash of the filename, used for speeding up hashing in incremental compilation.
908918
pub name_hash: u128,
919+
/// Indicates which crate this `SourceFile` was imported from.
920+
pub cnum: CrateNum,
909921
}
910922

911923
impl Encodable for SourceFile {
@@ -972,7 +984,8 @@ impl Encodable for SourceFile {
972984
s.emit_struct_field("multibyte_chars", 6, |s| self.multibyte_chars.encode(s))?;
973985
s.emit_struct_field("non_narrow_chars", 7, |s| self.non_narrow_chars.encode(s))?;
974986
s.emit_struct_field("name_hash", 8, |s| self.name_hash.encode(s))?;
975-
s.emit_struct_field("normalized_pos", 9, |s| self.normalized_pos.encode(s))
987+
s.emit_struct_field("normalized_pos", 9, |s| self.normalized_pos.encode(s))?;
988+
s.emit_struct_field("cnum", 10, |s| self.cnum.encode(s))
976989
})
977990
}
978991
}
@@ -1022,24 +1035,24 @@ impl Decodable for SourceFile {
10221035
let name_hash: u128 = d.read_struct_field("name_hash", 8, |d| Decodable::decode(d))?;
10231036
let normalized_pos: Vec<NormalizedPos> =
10241037
d.read_struct_field("normalized_pos", 9, |d| Decodable::decode(d))?;
1038+
let cnum: CrateNum = d.read_struct_field("cnum", 10, |d| Decodable::decode(d))?;
10251039
Ok(SourceFile {
10261040
name,
10271041
name_was_remapped,
10281042
unmapped_path: None,
1029-
// `crate_of_origin` has to be set by the importer.
1030-
// This value matches up with `rustc_hir::def_id::INVALID_CRATE`.
1031-
// That constant is not available here, unfortunately.
1032-
crate_of_origin: std::u32::MAX - 1,
10331043
start_pos,
10341044
end_pos,
10351045
src: None,
10361046
src_hash,
1037-
external_src: Lock::new(ExternalSource::AbsentOk),
1047+
// Unused - the metadata decoder will construct
1048+
// a new SourceFile, filling in `external_src` properly
1049+
external_src: Lock::new(ExternalSource::Unneeded),
10381050
lines,
10391051
multibyte_chars,
10401052
non_narrow_chars,
10411053
normalized_pos,
10421054
name_hash,
1055+
cnum,
10431056
})
10441057
})
10451058
}
@@ -1081,7 +1094,6 @@ impl SourceFile {
10811094
name,
10821095
name_was_remapped,
10831096
unmapped_path: Some(unmapped_path),
1084-
crate_of_origin: 0,
10851097
src: Some(Lrc::new(src)),
10861098
src_hash,
10871099
external_src: Lock::new(ExternalSource::Unneeded),
@@ -1092,6 +1104,7 @@ impl SourceFile {
10921104
non_narrow_chars,
10931105
normalized_pos,
10941106
name_hash,
1107+
cnum: LOCAL_CRATE,
10951108
}
10961109
}
10971110

@@ -1109,21 +1122,27 @@ impl SourceFile {
11091122
where
11101123
F: FnOnce() -> Option<String>,
11111124
{
1112-
if *self.external_src.borrow() == ExternalSource::AbsentOk {
1125+
if matches!(
1126+
*self.external_src.borrow(),
1127+
ExternalSource::Foreign { kind: ExternalSourceKind::AbsentOk, .. }
1128+
) {
11131129
let src = get_src();
11141130
let mut external_src = self.external_src.borrow_mut();
11151131
// Check that no-one else have provided the source while we were getting it
1116-
if *external_src == ExternalSource::AbsentOk {
1132+
if let ExternalSource::Foreign {
1133+
kind: src_kind @ ExternalSourceKind::AbsentOk, ..
1134+
} = &mut *external_src
1135+
{
11171136
if let Some(src) = src {
11181137
let mut hasher: StableHasher = StableHasher::new();
11191138
hasher.write(src.as_bytes());
11201139

11211140
if hasher.finish::<u128>() == self.src_hash {
1122-
*external_src = ExternalSource::Present(src);
1141+
*src_kind = ExternalSourceKind::Present(src);
11231142
return true;
11241143
}
11251144
} else {
1126-
*external_src = ExternalSource::AbsentErr;
1145+
*src_kind = ExternalSourceKind::AbsentErr;
11271146
}
11281147

11291148
false

‎src/librustc_span/source_map.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -296,14 +296,16 @@ impl SourceMap {
296296
&self,
297297
filename: FileName,
298298
name_was_remapped: bool,
299-
crate_of_origin: u32,
300299
src_hash: u128,
301300
name_hash: u128,
302301
source_len: usize,
302+
cnum: CrateNum,
303303
mut file_local_lines: Vec<BytePos>,
304304
mut file_local_multibyte_chars: Vec<MultiByteChar>,
305305
mut file_local_non_narrow_chars: Vec<NonNarrowChar>,
306306
mut file_local_normalized_pos: Vec<NormalizedPos>,
307+
original_start_pos: BytePos,
308+
original_end_pos: BytePos,
307309
) -> Lrc<SourceFile> {
308310
let start_pos = self
309311
.allocate_address_space(source_len)
@@ -332,17 +334,21 @@ impl SourceMap {
332334
name: filename,
333335
name_was_remapped,
334336
unmapped_path: None,
335-
crate_of_origin,
336337
src: None,
337338
src_hash,
338-
external_src: Lock::new(ExternalSource::AbsentOk),
339+
external_src: Lock::new(ExternalSource::Foreign {
340+
kind: ExternalSourceKind::AbsentOk,
341+
original_start_pos,
342+
original_end_pos,
343+
}),
339344
start_pos,
340345
end_pos,
341346
lines: file_local_lines,
342347
multibyte_chars: file_local_multibyte_chars,
343348
non_narrow_chars: file_local_non_narrow_chars,
344349
normalized_pos: file_local_normalized_pos,
345350
name_hash,
351+
cnum,
346352
});
347353

348354
let mut files = self.files.borrow_mut();
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#[macro_export]
2+
macro_rules! define_parse_error {
3+
() => {
4+
#[macro_export]
5+
macro_rules! parse_error {
6+
() => { parse error }
7+
}
8+
}
9+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
extern crate transitive_dep_three;
2+
3+
transitive_dep_three::define_parse_error!();
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// Tests that we properly serialize/deserialize spans from transitive dependencies
2+
// (e.g. imported SourceFiles)
3+
//
4+
// The order of these next lines is important, since we need
5+
// transitive_dep_two.rs to be able to reference transitive_dep_three.rs
6+
//
7+
// aux-build: transitive_dep_three.rs
8+
// aux-build: transitive_dep_two.rs
9+
// compile-flags: -Z macro-backtrace
10+
11+
extern crate transitive_dep_two;
12+
13+
transitive_dep_two::parse_error!(); //~ ERROR expected one of
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
error: expected one of `!` or `::`, found `error`
2+
--> $DIR/auxiliary/transitive_dep_three.rs:6:27
3+
|
4+
LL | / macro_rules! parse_error {
5+
LL | | () => { parse error }
6+
| | ^^^^^ expected one of `!` or `::`
7+
LL | | }
8+
| |_________- in this expansion of `transitive_dep_two::parse_error!`
9+
|
10+
::: $DIR/transitive-dep-span.rs:13:1
11+
|
12+
LL | transitive_dep_two::parse_error!();
13+
| -----------------------------------
14+
| |
15+
| in this macro invocation
16+
| in this macro invocation
17+
18+
error: aborting due to previous error
19+

0 commit comments

Comments
 (0)
Please sign in to comment.