diff options
| author | Niko Matsakis <niko@alum.mit.edu> | 2018-02-20 13:49:54 -0500 |
|---|---|---|
| committer | Niko Matsakis <niko@alum.mit.edu> | 2018-02-20 19:12:52 -0500 |
| commit | a47fd3df89c267829d96748b3bdff305f20d27d5 (patch) | |
| tree | 676d0df0845297a873c5e0a6620f464dea49a642 /src/libsyntax | |
| parent | 27a046e9338fb0455c33b13e8fe28da78212dedc (diff) | |
| download | rust-a47fd3df89c267829d96748b3bdff305f20d27d5.tar.gz rust-a47fd3df89c267829d96748b3bdff305f20d27d5.zip | |
make `#[unwind]` attribute specify expectations more clearly
You can now choose between the following: - `#[unwind(allowed)]` - `#[unwind(aborts)]` Per rust-lang/rust#48251, the default is `#[unwind(allowed)]`, though I think we should change this eventually.
Diffstat (limited to 'src/libsyntax')
| -rw-r--r-- | src/libsyntax/attr.rs | 45 | ||||
| -rw-r--r-- | src/libsyntax/diagnostic_list.rs | 27 | ||||
| -rw-r--r-- | src/libsyntax/feature_gate.rs | 2 |
3 files changed, 73 insertions, 1 deletions
diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index d18d6f5e6bd..d0822b69aa6 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -565,6 +565,51 @@ pub fn find_inline_attr(diagnostic: Option<&Handler>, attrs: &[Attribute]) -> In }) } +#[derive(Copy, Clone, PartialEq)] +pub enum UnwindAttr { + Allowed, + Aborts, +} + +/// Determine what `#[unwind]` attribute is present in `attrs`, if any. +pub fn find_unwind_attr(diagnostic: Option<&Handler>, attrs: &[Attribute]) -> Option<UnwindAttr> { + let syntax_error = |attr: &Attribute| { + mark_used(attr); + diagnostic.map(|d| { + span_err!(d, attr.span, E0633, "malformed `#[unwind]` attribute"); + }); + None + }; + + attrs.iter().fold(None, |ia, attr| { + if attr.path != "unwind" { + return ia; + } + let meta = match attr.meta() { + Some(meta) => meta.node, + None => return ia, + }; + match meta { + MetaItemKind::Word => { + syntax_error(attr) + } + MetaItemKind::List(ref items) => { + mark_used(attr); + if items.len() != 1 { + syntax_error(attr) + } else if list_contains_name(&items[..], "allowed") { + Some(UnwindAttr::Allowed) + } else if list_contains_name(&items[..], "aborts") { + Some(UnwindAttr::Aborts) + } else { + syntax_error(attr) + } + } + _ => ia, + } + }) +} + /// True if `#[inline]` or `#[inline(always)]` is present in `attrs`. pub fn requests_inline(attrs: &[Attribute]) -> bool { match find_inline_attr(None, attrs) { diff --git a/src/libsyntax/diagnostic_list.rs b/src/libsyntax/diagnostic_list.rs index d841281e485..84ab0336f16 100644 --- a/src/libsyntax/diagnostic_list.rs +++ b/src/libsyntax/diagnostic_list.rs @@ -342,6 +342,33 @@ fn main() { ``` "##, +E0633: r##" +The `unwind` attribute was malformed. + +Erroneous code example: + +```ignore (compile_fail not working here; see Issue #43707) +#[unwind()] // error: expected one argument +pub extern fn something() {} + +fn main() {} +``` + +The `#[unwind]` attribute should be used as follows: + +- `#[unwind(aborts)]` -- specifies that if a non-Rust ABI function + should abort the process if it attempts to unwind. This is the safer + and preferred option. + +- `#[unwind(allowed)]` -- specifies that a non-Rust ABI function + should be allowed to unwind. This can easily result in Undefined + Behavior (UB), so be careful. + +NB. The default behavior here is "allowed", but this is unspecified +and likely to change in the future. + +"##, + } register_diagnostics! { diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 3b137f9570a..f1d0a70a22c 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -233,7 +233,7 @@ declare_features! ( // allow `extern "platform-intrinsic" { ... }` (active, platform_intrinsics, "1.4.0", Some(27731)), - // allow `#[unwind]` + // allow `#[unwind(..)]` // rust runtime internal (active, unwind_attributes, "1.4.0", None), |
