lib.rs 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. #![deny(warnings)]
  2. extern crate proc_macro;
  3. #[macro_use]
  4. extern crate quote;
  5. extern crate core;
  6. extern crate proc_macro2;
  7. #[macro_use]
  8. extern crate syn;
  9. use proc_macro2::Span;
  10. use syn::{parse, spanned::Spanned, ItemFn, ReturnType, Type, Visibility};
  11. use proc_macro::TokenStream;
  12. /// Attribute to declare the entry point of the program
  13. ///
  14. /// **IMPORTANT**: This attribute must appear exactly *once* in the dependency graph. Also, if you
  15. /// are using Rust 1.30 the attribute must be used on a reachable item (i.e. there must be no
  16. /// private modules between the item and the root of the crate); if the item is in the root of the
  17. /// crate you'll be fine. This reachability restriction doesn't apply to Rust 1.31 and newer releases.
  18. ///
  19. /// The specified function will be called by the reset handler *after* RAM has been initialized.
  20. /// If present, the FPU will also be enabled before the function is called.
  21. ///
  22. /// The type of the specified function must be `[unsafe] fn() -> !` (never ending function)
  23. ///
  24. /// # Properties
  25. ///
  26. /// The entry point will be called by the reset handler. The program can't reference to the entry
  27. /// point, much less invoke it.
  28. ///
  29. /// # Examples
  30. ///
  31. /// - Simple entry point
  32. ///
  33. /// ``` no_run
  34. /// # #![no_main]
  35. /// # use riscv_rt_macros::entry;
  36. /// #[entry]
  37. /// fn main() -> ! {
  38. /// loop {
  39. /// /* .. */
  40. /// }
  41. /// }
  42. /// ```
  43. #[proc_macro_attribute]
  44. pub fn entry(args: TokenStream, input: TokenStream) -> TokenStream {
  45. let f = parse_macro_input!(input as ItemFn);
  46. // check the function signature
  47. let valid_signature = f.sig.constness.is_none()
  48. && f.sig.asyncness.is_none()
  49. && f.vis == Visibility::Inherited
  50. && f.sig.abi.is_none()
  51. && f.sig.inputs.is_empty()
  52. && f.sig.generics.params.is_empty()
  53. && f.sig.generics.where_clause.is_none()
  54. && f.sig.variadic.is_none()
  55. && match f.sig.output {
  56. ReturnType::Default => false,
  57. ReturnType::Type(_, ref ty) => match **ty {
  58. Type::Never(_) => true,
  59. _ => false,
  60. },
  61. };
  62. if !valid_signature {
  63. return parse::Error::new(
  64. f.span(),
  65. "`#[entry]` function must have signature `[unsafe] fn() -> !`",
  66. )
  67. .to_compile_error()
  68. .into();
  69. }
  70. if !args.is_empty() {
  71. return parse::Error::new(Span::call_site(), "This attribute accepts no arguments")
  72. .to_compile_error()
  73. .into();
  74. }
  75. // XXX should we blacklist other attributes?
  76. let attrs = f.attrs;
  77. let unsafety = f.sig.unsafety;
  78. let stmts = f.block.stmts;
  79. quote!(
  80. #[export_name = "main"]
  81. #(#attrs)*
  82. pub #unsafety fn __risc_v_rt__main() -> ! {
  83. #(#stmts)*
  84. }
  85. )
  86. .into()
  87. }
  88. /// Attribute to mark which function will be called at the beginning of the reset handler.
  89. ///
  90. /// **IMPORTANT**: This attribute can appear at most *once* in the dependency graph. Also, if you
  91. /// are using Rust 1.30 the attribute must be used on a reachable item (i.e. there must be no
  92. /// private modules between the item and the root of the crate); if the item is in the root of the
  93. /// crate you'll be fine. This reachability restriction doesn't apply to Rust 1.31 and newer
  94. /// releases.
  95. ///
  96. /// The function must have the signature of `unsafe fn()`.
  97. ///
  98. /// The function passed will be called before static variables are initialized. Any access of static
  99. /// variables will result in undefined behavior.
  100. ///
  101. /// # Examples
  102. ///
  103. /// ```
  104. /// # use riscv_rt_macros::pre_init;
  105. /// #[pre_init]
  106. /// unsafe fn before_main() {
  107. /// // do something here
  108. /// }
  109. ///
  110. /// # fn main() {}
  111. /// ```
  112. #[proc_macro_attribute]
  113. pub fn pre_init(args: TokenStream, input: TokenStream) -> TokenStream {
  114. let f = parse_macro_input!(input as ItemFn);
  115. // check the function signature
  116. let valid_signature = f.sig.constness.is_none()
  117. && f.sig.asyncness.is_none()
  118. && f.vis == Visibility::Inherited
  119. && f.sig.unsafety.is_some()
  120. && f.sig.abi.is_none()
  121. && f.sig.inputs.is_empty()
  122. && f.sig.generics.params.is_empty()
  123. && f.sig.generics.where_clause.is_none()
  124. && f.sig.variadic.is_none()
  125. && match f.sig.output {
  126. ReturnType::Default => true,
  127. ReturnType::Type(_, ref ty) => match **ty {
  128. Type::Tuple(ref tuple) => tuple.elems.is_empty(),
  129. _ => false,
  130. },
  131. };
  132. if !valid_signature {
  133. return parse::Error::new(
  134. f.span(),
  135. "`#[pre_init]` function must have signature `unsafe fn()`",
  136. )
  137. .to_compile_error()
  138. .into();
  139. }
  140. if !args.is_empty() {
  141. return parse::Error::new(Span::call_site(), "This attribute accepts no arguments")
  142. .to_compile_error()
  143. .into();
  144. }
  145. // XXX should we blacklist other attributes?
  146. let attrs = f.attrs;
  147. let ident = f.sig.ident;
  148. let block = f.block;
  149. quote!(
  150. #[export_name = "__pre_init"]
  151. #(#attrs)*
  152. pub unsafe fn #ident() #block
  153. )
  154. .into()
  155. }