diff --git a/compiler/prog_data.m b/compiler/prog_data.m index d255068d6..95f1be356 100644 --- a/compiler/prog_data.m +++ b/compiler/prog_data.m @@ -535,6 +535,13 @@ pragma_foreign_code_attributes). :- mode set_thread_safe(in, in, out) is det. +:- pred tabled_for_io(pragma_foreign_code_attributes, tabled_for_io). +:- mode tabled_for_io(in, out) is det. + +:- pred set_tabled_for_io(pragma_foreign_code_attributes, tabled_for_io, + pragma_foreign_code_attributes). +:- mode set_tabled_for_io(in, in, out) is det. + % For pragma c_code, there are two different calling conventions, % one for C code that may recursively call Mercury code, and another % more efficient one for the case when we know that the C code will @@ -550,6 +557,10 @@ ---> not_thread_safe ; thread_safe. +:- type tabled_for_io + ---> not_tabled_for_io + ; tabled_for_io. + :- type pragma_var ---> pragma_var(prog_var, string, mode). % variable, name, mode @@ -924,24 +935,30 @@ :- type pragma_foreign_code_attributes ---> attributes( - may_call_mercury, - thread_safe + may_call_mercury :: may_call_mercury, + thread_safe :: thread_safe, + tabled_for_io :: tabled_for_io ). -default_attributes(attributes(may_call_mercury, not_thread_safe)). +default_attributes(attributes(may_call_mercury, not_thread_safe, + not_tabled_for_io)). may_call_mercury(Attrs, MayCallMercury) :- - Attrs = attributes(MayCallMercury, _). + MayCallMercury = Attrs ^ may_call_mercury. thread_safe(Attrs, ThreadSafe) :- - Attrs = attributes(_, ThreadSafe). + ThreadSafe = Attrs ^ thread_safe. + +tabled_for_io(Attrs, TabledForIo) :- + TabledForIo = Attrs ^ tabled_for_io. set_may_call_mercury(Attrs0, MayCallMercury, Attrs) :- - Attrs0 = attributes(_, ThreadSafe), - Attrs = attributes(MayCallMercury, ThreadSafe). + Attrs = Attrs0 ^ may_call_mercury := MayCallMercury. set_thread_safe(Attrs0, ThreadSafe, Attrs) :- - Attrs0 = attributes(MayCallMercury, _), - Attrs = attributes(MayCallMercury, ThreadSafe). + Attrs = Attrs0 ^ thread_safe := ThreadSafe. + +set_tabled_for_io(Attrs0, TabledForIo, Attrs) :- + Attrs = Attrs0 ^ tabled_for_io := TabledForIo. %-----------------------------------------------------------------------------% diff --git a/compiler/prog_io_pragma.m b/compiler/prog_io_pragma.m index 98656d68a..9a0169c1f 100644 --- a/compiler/prog_io_pragma.m +++ b/compiler/prog_io_pragma.m @@ -820,7 +820,7 @@ parse_pragma_keyword(ExpectedKeyword, Term, StringArg, StartContext) :- :- type collected_pragma_c_code_attribute ---> may_call_mercury(may_call_mercury) ; thread_safe(thread_safe) - . + ; tabled_for_io(tabled_for_io). :- pred parse_pragma_c_code_attributes_term(term, pragma_foreign_code_attributes). @@ -845,10 +845,21 @@ parse_pragma_c_code_attributes_term(Term, Attributes) :- % XXX an error message would be nice fail ; - set_thread_safe(Attributes1, thread_safe, Attributes) + set_thread_safe(Attributes1, thread_safe, Attributes2) ) ; - Attributes = Attributes1 + Attributes2 = Attributes1 + ), + ( list__member(tabled_for_io(tabled_for_io), AttrList) -> + ( list__member(tabled_for_io(not_tabled_for_io), AttrList) -> + % XXX an error message would be nice + fail + ; + set_tabled_for_io(Attributes2, tabled_for_io, + Attributes) + ) + ; + Attributes = Attributes2 ). :- pred parse_pragma_c_code_attributes_term0(term, @@ -881,6 +892,8 @@ parse_single_pragma_c_code_attribute(Term, Flag) :- Flag = may_call_mercury(MayCallMercury) ; parse_threadsafe(Term, ThreadSafe) -> Flag = thread_safe(ThreadSafe) + ; parse_tabled_for_io(Term, TabledForIo) -> + Flag = tabled_for_io(TabledForIo) ; fail ). @@ -905,6 +918,14 @@ parse_threadsafe(term__functor(term__atom("thread_safe"), [], _), parse_threadsafe(term__functor(term__atom("not_thread_safe"), [], _), not_thread_safe). +:- pred parse_tabled_for_io(term, tabled_for_io). +:- mode parse_tabled_for_io(in, out) is semidet. + +parse_tabled_for_io(term__functor(term__atom("tabled_for_io"), [], _), + tabled_for_io). +parse_tabled_for_io(term__functor(term__atom("not_tabled_for_io"), [], _), + not_tabled_for_io). + % parse a pragma c_code declaration :- pred parse_pragma_foreign_code(module_name, foreign_language, diff --git a/tests/valid/Mmakefile b/tests/valid/Mmakefile index 30969e81b..d36d08756 100644 --- a/tests/valid/Mmakefile +++ b/tests/valid/Mmakefile @@ -135,6 +135,7 @@ OTHER_SOURCES= \ switch_detection_bug.m \ switch_detection_bug2.m \ switches.m \ + tabled_for_io.m \ tricky_assert2.m \ tricky_ite.m \ two_pragma_c_codes.m \ diff --git a/tests/valid/tabled_for_io.m b/tests/valid/tabled_for_io.m new file mode 100644 index 000000000..a84d3118f --- /dev/null +++ b/tests/valid/tabled_for_io.m @@ -0,0 +1,19 @@ +% A test for the case where we have pragma(c_code, ...) decs for different +% modes of the same pred. + +:- module tabled_for_io. + +:- interface. + +:- import_module io. + +:- pred test(int::in, int::out, io__state::di, io__state::uo) is det. + +:- implementation. + +:- pragma c_code(test(A::in, B::out, IO0::di, IO::uo), + [will_not_call_mercury, tabled_for_io], +" + B = A; + IO = IO0; +").