123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413(**************************************************************************)(* *)(* OCaml *)(* *)(* Alain Frisch, LexiFi *)(* *)(* Copyright 2012 Institut National de Recherche en Informatique et *)(* en Automatique. *)(* *)(* All rights reserved. This file is distributed under the terms of *)(* the GNU Lesser General Public License version 2.1, with the *)(* special exception on linking described in the file LICENSE. *)(* *)(**************************************************************************)openAsttypesopenParsetreeopenAst_helpermoduleAttribute_table=Hashtbl.Make(structtypet=stringwith_loclethash:t->int=Hashtbl.hashletequal:t->t->bool=(=)end)letunused_attrs=Attribute_table.create128letmark_usedt=Attribute_table.removeunused_attrst(* [attr_order] is used to issue unused attribute warnings in the order the
attributes occur in the file rather than the random order of the hash table
*)letattr_ordera1a2=matchString.comparea1.loc.loc_start.pos_fnamea2.loc.loc_start.pos_fnamewith|0->Int.comparea1.loc.loc_start.pos_cnuma2.loc.loc_start.pos_cnum|n->nletcompiler_stops_before_attributes_consumed()=letstops_before_lambda=match!Clflags.stop_afterwith|None->false|Somepass->Clflags.Compiler_pass.(comparepassLambda)<0instops_before_lambda||!Clflags.print_typesletwarn_unused()=letkeys=List.of_seq(Attribute_table.to_seq_keysunused_attrs)inAttribute_table.clearunused_attrs;ifnot(compiler_stops_before_attributes_consumed())thenletkeys=List.sortattr_orderkeysinList.iter(funsloc->Location.prerr_warningsloc.loc(Warnings.Misplaced_attributesloc.txt))keys(* These are the attributes that are tracked in the builtin_attrs table for
misplaced attribute warnings. *)letbuiltin_attrs=["alert";"boxed";"deprecated";"deprecated_mutable";"explicit_arity";"immediate";"immediate64";"inline";"inlined";"noalloc";"poll";"ppwarning";"specialise";"specialised";"tailcall";"tail_mod_cons";"unboxed";"untagged";"unrolled";"warnerror";"warning";"warn_on_literal_pattern"]letbuiltin_attrs=lettbl=Hashtbl.create128inList.iter(funattr->Hashtbl.addtblattr())builtin_attrs;tblletdrop_ocaml_attr_prefixs=letlen=String.lengthsinifString.starts_with~prefix:"ocaml."s&&len>6thenString.subs6(len-6)elsesletis_builtin_attrs=Hashtbl.membuiltin_attrs(drop_ocaml_attr_prefixs)typecurrent_phase=Parser|Invariant_checkletregister_attrcurrent_phasename=matchcurrent_phasewith|Parserwhen!Clflags.all_ppx<>[]->()|Parser|Invariant_check->ifis_builtin_attrname.txtthenAttribute_table.replaceunused_attrsname()letstring_of_cstconst=matchconst.pconst_descwith|Pconst_string(s,_,_)->Somes|_->Noneletstring_of_payload=function|PStr[{pstr_desc=Pstr_eval({pexp_desc=Pexp_constantc},_)}]->string_of_cstc|_->Noneletstring_of_opt_payloadp=matchstring_of_payloadpwith|Somes->s|None->""moduleStyle=Misc.Styleleterror_of_extensionext=letsubmessage_frommain_locmain_txt=function|{pstr_desc=Pstr_extension(({txt=("ocaml.error"|"error");loc},p),_)}->beginmatchpwith|PStr([{pstr_desc=Pstr_eval({pexp_desc=Pexp_constant{pconst_desc=Pconst_string(msg,_,_);_}},_)}])->Location.msg~loc"%a"Format_doc.pp_print_textmsg|_->Location.msg~loc"Invalid syntax for sub-message of extension %a."Style.inline_codemain_txtend|{pstr_desc=Pstr_extension(({txt;loc},_),_)}->Location.msg~loc"Uninterpreted extension '%a'."Style.inline_codetxt|_->Location.msg~loc:main_loc"Invalid syntax for sub-message of extension %a."Style.inline_codemain_txtinmatchextwith|({txt=("ocaml.error"|"error")astxt;loc},p)->beginmatchpwith|PStr[]->raiseLocation.Already_displayed_error|PStr({pstr_desc=Pstr_eval({pexp_desc=Pexp_constant{pconst_desc=Pconst_string(msg,_,_)}},_)}::inner)->letsub=List.map(submessage_fromloctxt)innerinLocation.error_of_printer~loc~subFormat_doc.pp_print_textmsg|_->Location.errorf~loc"Invalid syntax for extension '%s'."txtend|({txt;loc},_)->Location.errorf~loc"Uninterpreted extension '%s'."txtletattr_equals_builtin{attr_name={txt;_};_}s=(* Check for attribute s or ocaml.s. Avoid allocating a fresh string. *)txt=s||(String.lengthtxt=6+String.lengths&&String.starts_with~prefix:"ocaml."txt&&String.ends_with~suffix:stxt)letmark_alert_useda=ifattr_equals_builtina"deprecated"||attr_equals_builtina"alert"thenmark_useda.attr_nameletmark_alerts_usedl=List.itermark_alert_usedlletmark_warn_on_literal_pattern_usedl=List.iter(funa->ifattr_equals_builtina"warn_on_literal_pattern"thenmark_useda.attr_name)lletmark_deprecated_mutable_usedl=List.iter(funa->ifattr_equals_builtina"deprecated_mutable"thenmark_useda.attr_name)lletmark_payload_attrs_usedpayload=letiter={Ast_iterator.default_iteratorwithattribute=funselfa->mark_useda.attr_name;Ast_iterator.default_iterator.attributeselfa}initer.payloaditerpayloadletkind_and_message=function|PStr[{pstr_desc=Pstr_eval({pexp_desc=Pexp_apply({pexp_desc=Pexp_ident{txt=Longident.Lidentid}},[Nolabel,{pexp_desc=Pexp_constant{pconst_desc=Pconst_string(s,_,_);_}}])},_)}]->Some(id,s)|PStr[{pstr_desc=Pstr_eval({pexp_desc=Pexp_ident{txt=Longident.Lidentid}},_)}]->Some(id,"")|_->Noneletcats1s2=ifs2=""thens1elses1^"\n"^s2letalert_attrx=ifattr_equals_builtinx"deprecated"thenSome(x,"deprecated",string_of_opt_payloadx.attr_payload)elseifattr_equals_builtinx"alert"thenbeginmatchkind_and_messagex.attr_payloadwith|Some(kind,message)->Some(x,kind,message)|None->None(* note: bad payloads detected by warning_attribute *)endelseNoneletalert_attrsl=List.filter_mapalert_attrlletalerts_of_attrsl=List.fold_left(funacc(_,kind,message)->letupd=function|None|Some""->Somemessage|Somes->Some(catsmessage)inMisc.String.Map.updatekindupdacc)Misc.String.Map.empty(alert_attrsl)letcheck_alertslocattrss=Misc.String.Map.iter(funkindmessage->Location.alertloc~kind(catsmessage))(alerts_of_attrsattrs)letcheck_alerts_inclusion~def~uselocattrs1attrs2s=letm2=alerts_of_attrsattrs2inMisc.String.Map.iter(funkindmsg->ifnot(Misc.String.Map.memkindm2)thenLocation.alert~def~use~kindloc(catsmsg))(alerts_of_attrsattrs1)letrecdeprecated_mutable_of_attrs=function|[]->None|attr::_whenattr_equals_builtinattr"deprecated_mutable"->Some(string_of_opt_payloadattr.attr_payload)|_::tl->deprecated_mutable_of_attrstlletcheck_deprecated_mutablelocattrss=matchdeprecated_mutable_of_attrsattrswith|None->()|Sometxt->Location.deprecatedloc(Printf.sprintf"mutating field %s"(catstxt))letcheck_deprecated_mutable_inclusion~def~uselocattrs1attrs2s=matchdeprecated_mutable_of_attrsattrs1,deprecated_mutable_of_attrsattrs2with|None,_|Some_,Some_->()|Sometxt,None->Location.deprecated~def~useloc(Printf.sprintf"mutating field %s"(catstxt))letrecattrs_of_sig=function|{psig_desc=Psig_attributea}::tl->a::attrs_of_sigtl|_->[]letalerts_of_sig~marksg=leta=attrs_of_sigsginifmarkthenmark_alerts_useda;alerts_of_attrsaletrecattrs_of_str=function|{pstr_desc=Pstr_attributea}::tl->a::attrs_of_strtl|_->[]letalerts_of_str~markstr=leta=attrs_of_strstrinifmarkthenmark_alerts_useda;alerts_of_attrsaletwarn_payloadloctxtmsg=Location.prerr_warningloc(Warnings.Attribute_payload(txt,msg))letwarning_attribute?(ppwarning=true)=letprocesslocnameerrflagpayload=mark_usedname;matchstring_of_payloadpayloadwith|Somes->begintryOption.iter(Location.prerr_alertloc)(Warnings.parse_optionserrflags)withArg.Badmsg->warn_payloadlocname.txtmsgend|None->warn_payloadlocname.txt"A single string literal is expected"inletprocess_alertlocname=function|PStr[{pstr_desc=Pstr_eval({pexp_desc=Pexp_constant{pconst_desc=Pconst_string(s,_,_);_}},_)}]->beginmark_usedname;tryWarnings.parse_alert_optionswithArg.Badmsg->warn_payloadlocname.txtmsgend|k->matchkind_and_messagekwith|Some("all",_)->warn_payloadlocname.txt"The alert name 'all' is reserved"|Some_->(* Do [mark_used] in the [Some] case only if Warning 53 is
disabled. Later, they will be marked used (provided they are in a
valid place) in [compile_common], when they are extracted to be
persisted inside the [.cmi] file. *)ifnot(Warnings.is_active(Misplaced_attribute""))thenmark_usedname|None->begin(* Do [mark_used] in the [None] case, which is just malformed and
covered by the "Invalid payload" warning. *)mark_usedname;warn_payloadlocname.txt"Invalid payload"endinfun({attr_name;attr_loc;attr_payload}asattr)->ifattr_equals_builtinattr"warning"thenprocessattr_locattr_namefalseattr_payloadelseifattr_equals_builtinattr"warnerror"thenprocessattr_locattr_nametrueattr_payloadelseifattr_equals_builtinattr"alert"thenprocess_alertattr_locattr_nameattr_payloadelseifppwarning&&attr_equals_builtinattr"ppwarning"thenbeginmatchattr_payloadwith|PStr[{pstr_desc=Pstr_eval({pexp_desc=Pexp_constant{pconst_desc=Pconst_string(s,_,_);_}},_);pstr_loc}]->(mark_usedattr_name;Location.prerr_warningpstr_loc(Warnings.Preprocessors))|_->(mark_usedattr_name;warn_payloadattr_locattr_name.txt"A single string literal is expected")endletwarning_scope?ppwarningattrsf=letprev=Warnings.backup()intryList.iter(warning_attribute?ppwarning)(List.revattrs);letret=f()inWarnings.restoreprev;retwithexn->Warnings.restoreprev;raiseexnlethas_attributenmattrs=List.exists(funa->ifattr_equals_builtinanmthen(mark_useda.attr_name;true)elsefalse)attrstypeattr_action=Mark_used_only|Returnletselect_attributesactionsattrs=List.filter(funa->List.exists(fun(nm,action)->attr_equals_builtinanm&&beginmark_useda.attr_name;action=Returnend)actions)attrsletwarn_on_literal_patternattrs=has_attribute"warn_on_literal_pattern"attrsletexplicit_arityattrs=has_attribute"explicit_arity"attrsletimmediateattrs=has_attribute"immediate"attrsletimmediate64attrs=has_attribute"immediate64"attrs(* The "ocaml.boxed (default)" and "ocaml.unboxed (default)"
attributes cannot be input by the user, they are added by the
compiler when applying the default setting. This is done to record
in the .cmi the default used by the compiler when compiling the
source file because the default can change between compiler
invocations. *)lethas_unboxedattrs=has_attribute"unboxed"attrslethas_boxedattrs=has_attribute"boxed"attrs