diff --git a/src/test/rustdoc/auxiliary/enum_primitive.rs b/src/test/rustdoc/auxiliary/enum_primitive.rs new file mode 100644 index 0000000000000..c265ae44f0dc0 --- /dev/null +++ b/src/test/rustdoc/auxiliary/enum_primitive.rs @@ -0,0 +1,210 @@ +// Copyright (c) 2015 Anders Kaseorg + +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// “Software”), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: + +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +//! This crate exports a macro `enum_from_primitive!` that wraps an +//! `enum` declaration and automatically adds an implementation of +//! `num::FromPrimitive` (reexported here), to allow conversion from +//! primitive integers to the enum. It therefore provides an +//! alternative to the built-in `#[derive(FromPrimitive)]`, which +//! requires the unstable `std::num::FromPrimitive` and is disabled in +//! Rust 1.0. +//! +//! # Example +//! +//! ``` +//! #[macro_use] extern crate enum_primitive; +//! extern crate num_traits; +//! use num_traits::FromPrimitive; +//! +//! enum_from_primitive! { +//! #[derive(Debug, PartialEq)] +//! enum FooBar { +//! Foo = 17, +//! Bar = 42, +//! Baz, +//! } +//! } +//! +//! fn main() { +//! assert_eq!(FooBar::from_i32(17), Some(FooBar::Foo)); +//! assert_eq!(FooBar::from_i32(42), Some(FooBar::Bar)); +//! assert_eq!(FooBar::from_i32(43), Some(FooBar::Baz)); +//! assert_eq!(FooBar::from_i32(91), None); +//! } +//! ``` + + +pub mod num_traits { + pub trait FromPrimitive: Sized { + fn from_i64(n: i64) -> Option; + fn from_u64(n: u64) -> Option; + } +} + +pub use std::option::Option; +pub use num_traits::FromPrimitive; + +/// Helper macro for internal use by `enum_from_primitive!`. +#[macro_export] +macro_rules! enum_from_primitive_impl_ty { + ($meth:ident, $ty:ty, $name:ident, $( $variant:ident )*) => { + #[allow(non_upper_case_globals, unused)] + fn $meth(n: $ty) -> $crate::Option { + $( if n == $name::$variant as $ty { + $crate::Option::Some($name::$variant) + } else )* { + $crate::Option::None + } + } + }; +} + +/// Helper macro for internal use by `enum_from_primitive!`. +#[macro_export] +#[macro_use(enum_from_primitive_impl_ty)] +macro_rules! enum_from_primitive_impl { + ($name:ident, $( $variant:ident )*) => { + impl $crate::FromPrimitive for $name { + enum_from_primitive_impl_ty! { from_i64, i64, $name, $( $variant )* } + enum_from_primitive_impl_ty! { from_u64, u64, $name, $( $variant )* } + } + }; +} + +/// Wrap this macro around an `enum` declaration to get an +/// automatically generated implementation of `num::FromPrimitive`. +#[macro_export] +#[macro_use(enum_from_primitive_impl)] +macro_rules! enum_from_primitive { + ( + $( #[$enum_attr:meta] )* + enum $name:ident { + $( $( #[$variant_attr:meta] )* $variant:ident ),+ + $( = $discriminator:expr, $( $( #[$variant_two_attr:meta] )* $variant_two:ident ),+ )* + } + ) => { + $( #[$enum_attr] )* + enum $name { + $( $( #[$variant_attr] )* $variant ),+ + $( = $discriminator, $( $( #[$variant_two_attr] )* $variant_two ),+ )* + } + enum_from_primitive_impl! { $name, $( $variant )+ $( $( $variant_two )+ )* } + }; + + ( + $( #[$enum_attr:meta] )* + enum $name:ident { + $( $( $( #[$variant_attr:meta] )* $variant:ident ),+ = $discriminator:expr ),* + } + ) => { + $( #[$enum_attr] )* + enum $name { + $( $( $( #[$variant_attr] )* $variant ),+ = $discriminator ),* + } + enum_from_primitive_impl! { $name, $( $( $variant )+ )* } + }; + + ( + $( #[$enum_attr:meta] )* + enum $name:ident { + $( $( #[$variant_attr:meta] )* $variant:ident ),+ + $( = $discriminator:expr, $( $( #[$variant_two_attr:meta] )* $variant_two:ident ),+ )*, + } + ) => { + $( #[$enum_attr] )* + enum $name { + $( $( #[$variant_attr] )* $variant ),+ + $( = $discriminator, $( $( #[$variant_two_attr] )* $variant_two ),+ )*, + } + enum_from_primitive_impl! { $name, $( $variant )+ $( $( $variant_two )+ )* } + }; + + ( + $( #[$enum_attr:meta] )* + enum $name:ident { + $( $( $( #[$variant_attr:meta] )* $variant:ident ),+ = $discriminator:expr ),+, + } + ) => { + $( #[$enum_attr] )* + enum $name { + $( $( $( #[$variant_attr] )* $variant ),+ = $discriminator ),+, + } + enum_from_primitive_impl! { $name, $( $( $variant )+ )+ } + }; + + ( + $( #[$enum_attr:meta] )* + pub enum $name:ident { + $( $( #[$variant_attr:meta] )* $variant:ident ),+ + $( = $discriminator:expr, $( $( #[$variant_two_attr:meta] )* $variant_two:ident ),+ )* + } + ) => { + $( #[$enum_attr] )* + pub enum $name { + $( $( #[$variant_attr] )* $variant ),+ + $( = $discriminator, $( $( #[$variant_two_attr] )* $variant_two ),+ )* + } + enum_from_primitive_impl! { $name, $( $variant )+ $( $( $variant_two )+ )* } + }; + + ( + $( #[$enum_attr:meta] )* + pub enum $name:ident { + $( $( $( #[$variant_attr:meta] )* $variant:ident ),+ = $discriminator:expr ),* + } + ) => { + $( #[$enum_attr] )* + pub enum $name { + $( $( $( #[$variant_attr] )* $variant ),+ = $discriminator ),* + } + enum_from_primitive_impl! { $name, $( $( $variant )+ )* } + }; + + ( + $( #[$enum_attr:meta] )* + pub enum $name:ident { + $( $( #[$variant_attr:meta] )* $variant:ident ),+ + $( = $discriminator:expr, $( $( #[$variant_two_attr:meta] )* $variant_two:ident ),+ )*, + } + ) => { + $( #[$enum_attr] )* + pub enum $name { + $( $( #[$variant_attr] )* $variant ),+ + $( = $discriminator, $( $( #[$variant_two_attr] )* $variant_two ),+ )*, + } + enum_from_primitive_impl! { $name, $( $variant )+ $( $( $variant_two )+ )* } + }; + + ( + $( #[$enum_attr:meta] )* + pub enum $name:ident { + $( $( $( #[$variant_attr:meta] )* $variant:ident ),+ = $discriminator:expr ),+, + } + ) => { + $( #[$enum_attr] )* + pub enum $name { + $( $( $( #[$variant_attr] )* $variant ),+ = $discriminator ),+, + } + enum_from_primitive_impl! { $name, $( $( $variant )+ )+ } + }; +} + diff --git a/src/test/rustdoc/no-stack-overflow-25295.rs b/src/test/rustdoc/no-stack-overflow-25295.rs new file mode 100644 index 0000000000000..37b0aca4b00ca --- /dev/null +++ b/src/test/rustdoc/no-stack-overflow-25295.rs @@ -0,0 +1,46 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// ensure this code doesn't stack overflow +// aux-build:enum_primitive.rs + +#[macro_use] extern crate enum_primitive; + +enum_from_primitive! { + pub enum Test { + A1,A2,A3,A4,A5,A6, + B1,B2,B3,B4,B5,B6, + C1,C2,C3,C4,C5,C6, + D1,D2,D3,D4,D5,D6, + E1,E2,E3,E4,E5,E6, + F1,F2,F3,F4,F5,F6, + G1,G2,G3,G4,G5,G6, + H1,H2,H3,H4,H5,H6, + I1,I2,I3,I4,I5,I6, + J1,J2,J3,J4,J5,J6, + K1,K2,K3,K4,K5,K6, + L1,L2,L3,L4,L5,L6, + M1,M2,M3,M4,M5,M6, + N1,N2,N3,N4,N5,N6, + O1,O2,O3,O4,O5,O6, + P1,P2,P3,P4,P5,P6, + Q1,Q2,Q3,Q4,Q5,Q6, + R1,R2,R3,R4,R5,R6, + S1,S2,S3,S4,S5,S6, + T1,T2,T3,T4,T5,T6, + U1,U2,U3,U4,U5,U6, + V1,V2,V3,V4,V5,V6, + W1,W2,W3,W4,W5,W6, + X1,X2,X3,X4,X5,X6, + Y1,Y2,Y3,Y4,Y5,Y6, + Z1,Z2,Z3,Z4,Z5,Z6, + } +} +