Skip to content

Commit 35501bd

Browse files
committed
Add attr tracking mechanism, but don't whitelist any attrs yet
1 parent 217d42e commit 35501bd

File tree

10 files changed

+192
-28
lines changed

10 files changed

+192
-28
lines changed

.depend

+8
Original file line numberDiff line numberDiff line change
@@ -290,15 +290,21 @@ parsing/builtin_attributes.cmo : \
290290
utils/misc.cmi \
291291
parsing/longident.cmi \
292292
parsing/location.cmi \
293+
utils/clflags.cmi \
293294
parsing/asttypes.cmi \
295+
parsing/ast_iterator.cmi \
296+
parsing/ast_helper.cmi \
294297
parsing/builtin_attributes.cmi
295298
parsing/builtin_attributes.cmx : \
296299
utils/warnings.cmx \
297300
parsing/parsetree.cmi \
298301
utils/misc.cmx \
299302
parsing/longident.cmx \
300303
parsing/location.cmx \
304+
utils/clflags.cmx \
301305
parsing/asttypes.cmi \
306+
parsing/ast_iterator.cmx \
307+
parsing/ast_helper.cmx \
302308
parsing/builtin_attributes.cmi
303309
parsing/builtin_attributes.cmi : \
304310
parsing/parsetree.cmi \
@@ -413,6 +419,7 @@ parsing/parser.cmo : \
413419
parsing/docstrings.cmi \
414420
utils/clflags.cmi \
415421
parsing/camlinternalMenhirLib.cmi \
422+
parsing/builtin_attributes.cmi \
416423
parsing/asttypes.cmi \
417424
parsing/ast_helper.cmi \
418425
parsing/parser.cmi
@@ -424,6 +431,7 @@ parsing/parser.cmx : \
424431
parsing/docstrings.cmx \
425432
utils/clflags.cmx \
426433
parsing/camlinternalMenhirLib.cmx \
434+
parsing/builtin_attributes.cmx \
427435
parsing/asttypes.cmi \
428436
parsing/ast_helper.cmx \
429437
parsing/parser.cmi

.depend.menhir

+25-8
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,28 @@
1-
parsing/parser.cmo : parsing/syntaxerr.cmi parsing/parsetree.cmi \
2-
parsing/longident.cmi parsing/location.cmi parsing/docstrings.cmi \
3-
utils/clflags.cmi parsing/asttypes.cmi parsing/ast_helper.cmi \
1+
parsing/parser.cmo : \
2+
parsing/syntaxerr.cmi \
3+
parsing/parsetree.cmi \
4+
parsing/longident.cmi \
5+
parsing/location.cmi \
6+
parsing/docstrings.cmi \
7+
utils/clflags.cmi \
8+
parsing/builtin_attributes.cmi \
9+
parsing/asttypes.cmi \
10+
parsing/ast_helper.cmi \
411
parsing/parser.cmi
5-
parsing/parser.cmx : parsing/syntaxerr.cmx parsing/parsetree.cmi \
6-
parsing/longident.cmx parsing/location.cmx parsing/docstrings.cmx \
7-
utils/clflags.cmx parsing/asttypes.cmi parsing/ast_helper.cmx \
12+
parsing/parser.cmx : \
13+
parsing/syntaxerr.cmx \
14+
parsing/parsetree.cmi \
15+
parsing/longident.cmx \
16+
parsing/location.cmx \
17+
parsing/docstrings.cmx \
18+
utils/clflags.cmx \
19+
parsing/builtin_attributes.cmx \
20+
parsing/asttypes.cmi \
21+
parsing/ast_helper.cmx \
822
parsing/parser.cmi
9-
parsing/parser.cmi : parsing/parsetree.cmi parsing/location.cmi \
23+
parsing/parser.cmi : \
24+
parsing/parsetree.cmi \
25+
parsing/longident.cmi \
26+
parsing/location.cmi \
1027
parsing/docstrings.cmi
11-
parsing/parser.ml parsing/parser.mli: parsing/ast_helper.cmi parsing/asttypes.cmi utils/clflags.cmi parsing/docstrings.cmi parsing/location.cmi parsing/longident.cmi parsing/parsetree.cmi parsing/syntaxerr.cmi
28+
parsing/parser.ml parsing/parser.mli: parsing/ast_helper.cmi parsing/asttypes.cmi parsing/builtin_attributes.cmi utils/clflags.cmi parsing/docstrings.cmi parsing/location.cmi parsing/longident.cmi parsing/parsetree.cmi parsing/syntaxerr.cmi

Makefile

+4-2
Original file line numberDiff line numberDiff line change
@@ -94,16 +94,16 @@ parsing_SOURCES = $(addprefix parsing/, \
9494
docstrings.mli docstrings.ml \
9595
syntaxerr.mli syntaxerr.ml \
9696
ast_helper.mli ast_helper.ml \
97+
ast_iterator.mli ast_iterator.ml \
98+
builtin_attributes.mli builtin_attributes.ml \
9799
camlinternalMenhirLib.mli camlinternalMenhirLib.ml \
98100
parser.mly \
99101
lexer.mll \
100102
pprintast.mli pprintast.ml \
101103
parse.mli parse.ml \
102104
printast.mli printast.ml \
103105
ast_mapper.mli ast_mapper.ml \
104-
ast_iterator.mli ast_iterator.ml \
105106
attr_helper.mli attr_helper.ml \
106-
builtin_attributes.mli builtin_attributes.ml \
107107
ast_invariants.mli ast_invariants.ml \
108108
depend.mli depend.ml)
109109

@@ -2106,6 +2106,8 @@ ocamlprof_SOURCES = \
21062106
docstrings.mli docstrings.ml \
21072107
syntaxerr.mli syntaxerr.ml \
21082108
ast_helper.mli ast_helper.ml \
2109+
ast_iterator.mli ast_iterator.ml \
2110+
builtin_attributes.mli builtin_attributes.ml \
21092111
camlinternalMenhirLib.mli camlinternalMenhirLib.ml \
21102112
parser.mli parser.ml \
21112113
lexer.mli lexer.ml \

driver/compile_common.ml

+2
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ let typecheck_intf info ast =
6060
sg);
6161
ignore (Includemod.signatures info.env ~mark:Mark_both sg sg);
6262
Typecore.force_delayed_checks ();
63+
Builtin_attributes.warn_unused ();
6364
Warnings.check_fatal ();
6465
tsg
6566

@@ -117,5 +118,6 @@ let implementation info ~backend =
117118
backend info typed
118119
end;
119120
end;
121+
Builtin_attributes.warn_unused ();
120122
Warnings.check_fatal ();
121123
)

dune

+2-2
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,8 @@
4949

5050
;; PARSING
5151
location longident docstrings syntaxerr ast_helper camlinternalMenhirLib
52-
parser lexer parse printast pprintast ast_mapper ast_iterator attr_helper
53-
builtin_attributes ast_invariants depend
52+
ast_iterator builtin_attributes parser lexer parse printast pprintast
53+
ast_mapper attr_helper ast_invariants depend
5454
; manual update: mli only files
5555
asttypes parsetree
5656

otherlibs/dynlink/Makefile

+2-1
Original file line numberDiff line numberDiff line change
@@ -93,12 +93,13 @@ COMPILERLIBS_SOURCES=\
9393
parsing/docstrings.ml \
9494
parsing/syntaxerr.ml \
9595
parsing/ast_helper.ml \
96+
parsing/ast_iterator.ml \
97+
parsing/builtin_attributes.ml \
9698
parsing/ast_mapper.ml \
9799
parsing/camlinternalMenhirLib.ml \
98100
parsing/parser.ml \
99101
parsing/lexer.ml \
100102
parsing/attr_helper.ml \
101-
parsing/builtin_attributes.ml \
102103
typing/ident.ml \
103104
typing/path.ml \
104105
typing/primitive.ml \

parsing/ast_invariants.ml

+9
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,14 @@ let iterator =
180180
"In object types, attaching attributes to inherited \
181181
subtypes is not allowed."
182182
in
183+
let attribute self attr =
184+
(* The change to `self` here avoids registering attributes within attributes
185+
for the purposes of warning 53, while keeping all the other invariant
186+
checks for attribute payloads. See comment on [attr_tracking_time] in
187+
[builtin_attributes.mli]. *)
188+
super.attribute { self with attribute = super.attribute } attr;
189+
Builtin_attributes.(register_attr Invariant_check attr.attr_name)
190+
in
183191
{ super with
184192
type_declaration
185193
; typ
@@ -195,6 +203,7 @@ let iterator =
195203
; signature_item
196204
; row_field
197205
; object_field
206+
; attribute
198207
}
199208

200209
let structure st = iterator.structure iterator st

parsing/builtin_attributes.ml

+76
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,72 @@
1515

1616
open Asttypes
1717
open Parsetree
18+
open Ast_helper
19+
20+
21+
module Attribute_table = Hashtbl.Make (struct
22+
type t = string with_loc
23+
24+
let hash : t -> int = Hashtbl.hash
25+
let equal : t -> t -> bool = (=)
26+
end)
27+
let unused_attrs = Attribute_table.create 128
28+
let mark_used t = Attribute_table.remove unused_attrs t
29+
30+
(* [attr_order] is used to issue unused attribute warnings in the order the
31+
attributes occur in the file rather than the random order of the hash table
32+
*)
33+
let attr_order a1 a2 =
34+
match String.compare a1.loc.loc_start.pos_fname a2.loc.loc_start.pos_fname
35+
with
36+
| 0 -> Int.compare a1.loc.loc_start.pos_cnum a2.loc.loc_start.pos_cnum
37+
| n -> n
38+
39+
let warn_unused () =
40+
let keys = List.of_seq (Attribute_table.to_seq_keys unused_attrs) in
41+
let keys = List.sort attr_order keys in
42+
List.iter (fun sloc ->
43+
Location.prerr_warning sloc.loc (Warnings.Misplaced_attribute sloc.txt))
44+
keys
45+
46+
(* These are the attributes that are tracked in the builtin_attrs table for
47+
misplaced attribute warnings. *)
48+
let builtin_attrs =
49+
[ (* "alert"; "ocaml.alert" *)
50+
(* ; "boxed"; "ocaml.boxed" *)
51+
(* ; "deprecated"; "ocaml.deprecated" *)
52+
(* ; "deprecated_mutable"; "ocaml.deprecated_mutable" *)
53+
(* ; "explicit_arity"; "ocaml.explicit_arity" *)
54+
(* ; "immediate"; "ocaml.immediate" *)
55+
(* ; "immediate64"; "ocaml.immediate64" *)
56+
(* ; "inline"; "ocaml.inline" *)
57+
(* ; "inlined"; "ocaml.inlined" *)
58+
(* ; "noalloc"; "ocaml.noalloc" *)
59+
(* ; "ppwarning"; "ocaml.ppwarning" *)
60+
(* ; "tailcall"; "ocaml.tailcall" *)
61+
(* ; "unboxed"; "ocaml.unboxed" *)
62+
(* ; "untagged"; "ocaml.untagged" *)
63+
(* ; "unrolled"; "ocaml.unrolled" *)
64+
(* ; "warnerror"; "ocaml.warnerror" *)
65+
(* ; "warning"; "ocaml.warning" *)
66+
(* ; "warn_on_literal_pattern"; "ocaml.warn_on_literal_pattern" *)
67+
]
68+
69+
let builtin_attrs =
70+
let tbl = Hashtbl.create 128 in
71+
List.iter (fun attr -> Hashtbl.add tbl attr ()) builtin_attrs;
72+
tbl
73+
74+
let is_builtin_attr s = Hashtbl.mem builtin_attrs s
75+
76+
type attr_tracking_time = Parser | Invariant_check
77+
78+
let register_attr attr_tracking_time name =
79+
match attr_tracking_time with
80+
| Parser when !Clflags.all_ppx <> [] -> ()
81+
| Parser | Invariant_check ->
82+
if is_builtin_attr name.txt then
83+
Attribute_table.replace unused_attrs name ()
1884

1985
let string_of_cst = function
2086
| Pconst_string(s, _, _) -> Some s
@@ -67,6 +133,16 @@ let error_of_extension ext =
67133
| ({txt; loc}, _) ->
68134
Location.errorf ~loc "Uninterpreted extension '%s'." txt
69135

136+
let mark_payload_attrs_used payload =
137+
let iter =
138+
{ Ast_iterator.default_iterator
139+
with attribute = fun self a ->
140+
mark_used a.attr_name;
141+
Ast_iterator.default_iterator.attribute self a
142+
}
143+
in
144+
iter.payload iter payload
145+
70146
let kind_and_message = function
71147
| PStr[
72148
{pstr_desc=

parsing/builtin_attributes.mli

+48-9
Original file line numberDiff line numberDiff line change
@@ -13,26 +13,65 @@
1313
(* *)
1414
(**************************************************************************)
1515

16-
(** Support for some of the builtin attributes
16+
(** Support for the builtin attributes:
1717
18-
- ocaml.deprecated
1918
- ocaml.alert
20-
- ocaml.error
21-
- ocaml.ppwarning
22-
- ocaml.warning
23-
- ocaml.warnerror
24-
- ocaml.explicit_arity (for camlp4/camlp5)
25-
- ocaml.warn_on_literal_pattern
19+
- ocaml.boxed
20+
- ocaml.deprecated
2621
- ocaml.deprecated_mutable
22+
- ocaml.explicit_arity
2723
- ocaml.immediate
2824
- ocaml.immediate64
29-
- ocaml.boxed / ocaml.unboxed
25+
- ocaml.inline
26+
- ocaml.inlined
27+
- ocaml.noalloc
28+
- ocaml.ppwarning
29+
- ocaml.tailcall
30+
- ocaml.unboxed
31+
- ocaml.untagged
32+
- ocaml.unrolled
33+
- ocaml.warnerror
34+
- ocaml.warning
35+
- ocaml.warn_on_literal_pattern
3036
3137
{b Warning:} this module is unstable and part of
3238
{{!Compiler_libs}compiler-libs}.
3339
3440
*)
3541

42+
43+
(** [register_attr] must be called on the locations of all attributes that
44+
should be tracked for the purpose of misplaced attribute warnings. In
45+
particular, it should be called on all attributes that are present in the
46+
source program except those that are contained in the payload of another
47+
attribute (because these may be left behind by a ppx and intentionally
48+
ignored by the compiler).
49+
50+
The [attr_tracking_time] argument indicates when the attr is being added for
51+
tracking - either when it is created in the parser or when we see it while
52+
running the check in the [Ast_invariants] module. This ensures that we
53+
track only attributes from the final version of the parse tree: we skip
54+
adding attributes at parse time if we can see that a ppx will be run later,
55+
because the [Ast_invariants] check is always run on the result of a ppx.
56+
57+
Note that the [Ast_invariants] check is also run on parse trees created from
58+
marshalled ast files if no ppx is being used, ensuring we don't miss
59+
attributes in that case.
60+
*)
61+
type attr_tracking_time = Parser | Invariant_check
62+
val register_attr : attr_tracking_time -> string Location.loc -> unit
63+
64+
(** Marks the attributes hiding in the payload of another attribute used, for
65+
the purposes of misplaced attribute warnings (see comment on
66+
[attr_tracking_time] above). In the parser, it's simplest to add these to
67+
the table and remove them later, rather than threading through state
68+
tracking whether we're in an attribute payload. *)
69+
val mark_payload_attrs_used : Parsetree.payload -> unit
70+
71+
(** Issue misplaced attribute warnings for all attributes created with
72+
[mk_internal] but not yet marked used. *)
73+
val warn_unused : unit -> unit
74+
3675
val check_alerts: Location.t -> Parsetree.attributes -> string -> unit
3776
val check_alerts_inclusion:
3877
def:Location.t -> use:Location.t -> Location.t -> Parsetree.attributes ->

parsing/parser.mly

+16-6
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,10 @@ let mkuplus ~oploc name arg =
167167
| _ ->
168168
Pexp_apply(mkoperator ~loc:oploc ("~" ^ name), [Nolabel, arg])
169169

170+
let mk_attr ~loc name payload =
171+
Builtin_attributes.(register_attr Parser name);
172+
Attr.mk ~loc name payload
173+
170174
(* TODO define an abstraction boundary between locations-as-pairs
171175
and locations-as-Location.t; it should be clear when we move from
172176
one world to the other *)
@@ -4037,17 +4041,17 @@ attr_id:
40374041
) { $1 }
40384042
;
40394043
attribute:
4040-
LBRACKETAT attr_id payload RBRACKET
4041-
{ Attr.mk ~loc:(make_loc $sloc) $2 $3 }
4044+
LBRACKETAT attr_id attr_payload RBRACKET
4045+
{ mk_attr ~loc:(make_loc $sloc) $2 $3 }
40424046
;
40434047
post_item_attribute:
4044-
LBRACKETATAT attr_id payload RBRACKET
4045-
{ Attr.mk ~loc:(make_loc $sloc) $2 $3 }
4048+
LBRACKETATAT attr_id attr_payload RBRACKET
4049+
{ mk_attr ~loc:(make_loc $sloc) $2 $3 }
40464050
;
40474051
floating_attribute:
4048-
LBRACKETATATAT attr_id payload RBRACKET
4052+
LBRACKETATATAT attr_id attr_payload RBRACKET
40494053
{ mark_symbol_docs $sloc;
4050-
Attr.mk ~loc:(make_loc $sloc) $2 $3 }
4054+
mk_attr ~loc:(make_loc $sloc) $2 $3 }
40514055
;
40524056
%inline post_item_attributes:
40534057
post_item_attribute*
@@ -4087,4 +4091,10 @@ payload:
40874091
| QUESTION pattern { PPat ($2, None) }
40884092
| QUESTION pattern WHEN seq_expr { PPat ($2, Some $4) }
40894093
;
4094+
attr_payload:
4095+
payload
4096+
{ Builtin_attributes.mark_payload_attrs_used $1;
4097+
$1
4098+
}
4099+
;
40904100
%%

0 commit comments

Comments
 (0)