@@ -34,7 +34,12 @@ impl TokenExpander {
3434 // FIXME switch these to ExpandResult as well
3535 TokenExpander :: Builtin ( it) => it. expand ( db, id, tt) . into ( ) ,
3636 TokenExpander :: BuiltinDerive ( it) => it. expand ( db, id, tt) . into ( ) ,
37- TokenExpander :: ProcMacro ( it) => it. expand ( db, id, tt) . into ( ) ,
37+ TokenExpander :: ProcMacro ( _) => {
38+ // We store the result in salsa db to prevent non-determinisc behavior in
39+ // some proc-macro implementation
40+ // See #4315 for details
41+ db. expand_proc_macro ( id. into ( ) ) . into ( )
42+ }
3843 }
3944 }
4045
@@ -75,6 +80,8 @@ pub trait AstDatabase: SourceDatabase {
7580
7681 #[ salsa:: interned]
7782 fn intern_eager_expansion ( & self , eager : EagerCallLoc ) -> EagerMacroId ;
83+
84+ fn expand_proc_macro ( & self , call : MacroCallId ) -> Result < tt:: Subtree , mbe:: ExpandError > ;
7885}
7986
8087/// This expands the given macro call, but with different arguments. This is
@@ -216,6 +223,33 @@ fn macro_expand_with_arg(
216223 ( Some ( Arc :: new ( tt) ) , err. map ( |e| format ! ( "{:?}" , e) ) )
217224}
218225
226+ pub ( crate ) fn expand_proc_macro (
227+ db : & dyn AstDatabase ,
228+ id : MacroCallId ,
229+ ) -> Result < tt:: Subtree , mbe:: ExpandError > {
230+ let lazy_id = match id {
231+ MacroCallId :: LazyMacro ( id) => id,
232+ MacroCallId :: EagerMacro ( _) => unreachable ! ( ) ,
233+ } ;
234+
235+ let loc = db. lookup_intern_macro ( lazy_id) ;
236+ let macro_arg = match db. macro_arg ( id) {
237+ Some ( it) => it,
238+ None => {
239+ return Err (
240+ tt:: ExpansionError :: Unknown ( "No arguments for proc-macro" . to_string ( ) ) . into ( )
241+ )
242+ }
243+ } ;
244+
245+ let expander = match loc. def . kind {
246+ MacroDefKind :: CustomDerive ( expander) => expander,
247+ _ => unreachable ! ( ) ,
248+ } ;
249+
250+ expander. expand ( db, lazy_id, & macro_arg. 0 )
251+ }
252+
219253pub ( crate ) fn parse_or_expand ( db : & dyn AstDatabase , file_id : HirFileId ) -> Option < SyntaxNode > {
220254 match file_id. 0 {
221255 HirFileIdRepr :: FileId ( file_id) => Some ( db. parse ( file_id) . tree ( ) . syntax ( ) . clone ( ) ) ,
0 commit comments