[clang] do not translate dependent types

Summary:
Attempting to translate these will not go well as the declaration still depends
on some template arguments. Added a test that was previously crashing the
frontend.

Also extend the catching of "Unimplemented" and other errors to `translate_one_decl` as it was useful to debug this issue. In particular, reraise all exceptions and log some additional context when doing so.

update-submodule: facebook-clang-plugins

Reviewed By: mbouaziz

Differential Revision: D5976357

fbshipit-source-id: fca8e38
master
Jules Villard 7 years ago committed by Facebook Github Bot
parent eff7bb5bdf
commit 2d644b36af

@ -1 +1 @@
Subproject commit 5f2042abe6cf15e2a17741259fa08c55bf61fb1b Subproject commit 18ea5ae4205367ba3411210cb644ac983323818a

@ -233,9 +233,9 @@ let environment_info fmt = log ~to_console:false environment_info_file_fmts fmt
let external_warning fmt = log ~to_console:(not Config.quiet) external_warning_file_fmts fmt let external_warning fmt = log ~to_console:(not Config.quiet) external_warning_file_fmts fmt
let external_error fmt = log ~to_console:(not Config.quiet) external_error_file_fmts fmt let external_error fmt = log ~to_console:true external_error_file_fmts fmt
let internal_error fmt = log ~to_console:Config.developer_mode internal_error_file_fmts fmt let internal_error fmt = log ~to_console:true internal_error_file_fmts fmt
(** Type of location in ml source: __POS__ *) (** Type of location in ml source: __POS__ *)
type ml_loc = string * int * int * int type ml_loc = string * int * int * int

@ -222,17 +222,17 @@ and get_record_struct_type tenv definition_decl : Typ.desc =
| Some _ | Some _
-> sil_desc (* just reuse what is already in tenv *) -> sil_desc (* just reuse what is already in tenv *)
| None | None
-> let is_complete_definition = record_decl_info.Clang_ast_t.rdi_is_complete_definition in -> let is_translatable_definition =
let open Clang_ast_t in
record_decl_info.rdi_is_complete_definition
&& not record_decl_info.rdi_is_dependent_type
in
let extra_fields = let extra_fields =
if CTrans_models.is_objc_memory_model_controlled (Typ.Name.name sil_typename) then if CTrans_models.is_objc_memory_model_controlled (Typ.Name.name sil_typename) then
[Typ.Struct.objc_ref_counter_field] [Typ.Struct.objc_ref_counter_field]
else [] else []
in in
let annots = if is_translatable_definition then (
if Typ.Name.Cpp.is_class sil_typename then Annot.Class.cpp else Annot.Item.empty
(* No annotations for structs *)
in
if is_complete_definition then (
CAst_utils.update_sil_types_map type_ptr sil_desc ; CAst_utils.update_sil_types_map type_ptr sil_desc ;
let non_statics = get_struct_fields tenv definition_decl in let non_statics = get_struct_fields tenv definition_decl in
let fields = CGeneral_utils.append_no_duplicates_fields non_statics extra_fields in let fields = CGeneral_utils.append_no_duplicates_fields non_statics extra_fields in
@ -241,6 +241,10 @@ and get_record_struct_type tenv definition_decl : Typ.desc =
let methods = [] in let methods = [] in
(* C++ methods are not put into tenv (info isn't used) *) (* C++ methods are not put into tenv (info isn't used) *)
let supers = get_superclass_list_cpp tenv definition_decl in let supers = get_superclass_list_cpp tenv definition_decl in
let annots =
if Typ.Name.Cpp.is_class sil_typename then Annot.Class.cpp
else (* No annotations for structs *) Annot.Item.empty
in
Tenv.mk_struct tenv ~fields ~statics ~methods ~supers ~annots sil_typename |> ignore ; Tenv.mk_struct tenv ~fields ~statics ~methods ~supers ~annots sil_typename |> ignore ;
CAst_utils.update_sil_types_map type_ptr sil_desc ; CAst_utils.update_sil_types_map type_ptr sil_desc ;
sil_desc ) sil_desc )

@ -136,8 +136,8 @@ let get_desugared_type type_ptr =
let get_decl_from_typ_ptr typ_ptr = let get_decl_from_typ_ptr typ_ptr =
let typ_opt = get_desugared_type typ_ptr in let typ_opt = get_desugared_type typ_ptr in
let typ = match typ_opt with Some t -> t | _ -> assert false in let typ = match typ_opt with Some t -> t | _ -> assert false in
match typ with match (typ : Clang_ast_t.c_type) with
| Clang_ast_t.RecordType (_, decl_ptr) | Clang_ast_t.ObjCInterfaceType (_, decl_ptr) | RecordType (_, decl_ptr) | ObjCInterfaceType (_, decl_ptr)
-> get_decl decl_ptr -> get_decl decl_ptr
| _ | _
-> None -> None

@ -8,11 +8,35 @@
*) *)
open! IStd open! IStd
module F = Format
(** Translate declarations **) (** Translate declarations **)
module L = Logging module L = Logging
let protect ~f ~recover ~pp_context =
let log_and_recover ~print fmt =
recover () ;
(if print then L.internal_error else L.(debug Capture Quiet)) ("%a@\n" ^^ fmt) pp_context ()
in
try f () with
(* Always keep going in case of known limitations of the frontend, crash otherwise (by not
catching the exception) unless `--keep-going` was passed. Print errors we should fix
(t21762295) to the console. *)
| CFrontend_config.Unimplemented msg
-> log_and_recover ~print:false "Unimplemented feature:@\n %s@\n" msg
| CFrontend_config.IncorrectAssumption msg
-> (* FIXME(t21762295): we do not expect this to happen but it does *)
log_and_recover ~print:true "Known incorrect assumption in the frontend: %s@\n" msg
| CTrans_utils.Self.SelfClassException class_name
-> (* FIXME(t21762295): we do not expect this to happen but it does *)
log_and_recover ~print:true "Unexpected SelfClassException %a@\n" Typ.Name.pp class_name
| exn
-> let trace = Exn.backtrace () in
reraise_if exn ~f:(fun () ->
L.internal_error "%a: %a@\n%!" pp_context () Exn.pp exn ; not Config.keep_going ) ;
log_and_recover ~print:true "Frontend error: %a@\nBacktrace:@\n%s" Exn.pp exn trace
module CFrontend_decl_funct (T : CModule_type.CTranslation) : CModule_type.CFrontend = struct module CFrontend_decl_funct (T : CModule_type.CTranslation) : CModule_type.CFrontend = struct
let model_exists procname = Specs.summary_exists_in_models procname && not Config.models_mode let model_exists procname = Specs.summary_exists_in_models procname && not Config.models_mode
@ -21,17 +45,17 @@ module CFrontend_decl_funct (T : CModule_type.CTranslation) : CModule_type.CFron
body has_return_param is_objc_method outer_context_opt extra_instrs = body has_return_param is_objc_method outer_context_opt extra_instrs =
L.(debug Capture Verbose) L.(debug Capture Verbose)
"@\n@\n>>---------- ADDING METHOD: '%a' ---------<<@\n@\n" Typ.Procname.pp procname ; "@\n@\n>>---------- ADDING METHOD: '%a' ---------<<@\n@\n" Typ.Procname.pp procname ;
let handle_frontend_failure ~print fmt = let recover () =
Cfg.remove_proc_desc cfg procname ; Cfg.remove_proc_desc cfg procname ;
CMethod_trans.create_external_procdesc cfg procname is_objc_method None ; CMethod_trans.create_external_procdesc cfg procname is_objc_method None
(if print then L.internal_error else L.(debug Capture Quiet)) in
("Aborting translation of method '%a':@\n" ^^ fmt) Typ.Procname.pp procname let pp_context fmt () =
F.fprintf fmt "Aborting translation of method '%a'" Typ.Procname.pp procname
in in
try let f () =
match Cfg.find_proc_desc_from_name cfg procname with match Cfg.find_proc_desc_from_name cfg procname with
| Some procdesc | Some procdesc when Procdesc.is_defined procdesc && not (model_exists procname)
-> if Procdesc.is_defined procdesc && not (model_exists procname) then -> let vars_to_destroy = CTrans_utils.Scope.compute_vars_to_destroy body in
let vars_to_destroy = CTrans_utils.Scope.compute_vars_to_destroy body in
let context = let context =
CContext.create_context trans_unit_ctx tenv cg cfg procdesc class_decl_opt CContext.create_context trans_unit_ctx tenv cg cfg procdesc class_decl_opt
has_return_param is_objc_method outer_context_opt vars_to_destroy has_return_param is_objc_method outer_context_opt vars_to_destroy
@ -49,24 +73,10 @@ module CFrontend_decl_funct (T : CModule_type.CTranslation) : CModule_type.CFron
(Procdesc.get_locals procdesc) ; (Procdesc.get_locals procdesc) ;
Procdesc.node_set_succs_exn procdesc start_node meth_body_nodes [] ; Procdesc.node_set_succs_exn procdesc start_node meth_body_nodes [] ;
Cg.add_defined_node (CContext.get_cg context) (Procdesc.get_proc_name procdesc) Cg.add_defined_node (CContext.get_cg context) (Procdesc.get_proc_name procdesc)
| None | _
-> () -> ()
with in
(* Always keep going in case of known limitations of the frontend, crash otherwise (by not protect ~f ~recover ~pp_context
catching the exception) unless `--keep-going` was passed. Print errors we should fix
(t21762295) to the console. *)
| CFrontend_config.Unimplemented msg
-> handle_frontend_failure ~print:false "Unimplemented feature:@\n %s@\n" msg
| CFrontend_config.IncorrectAssumption msg
-> (* FIXME(t21762295): we do not expect this to happen but it does *)
handle_frontend_failure ~print:true "Known incorrect assumption in the frontend: %s@\n" msg
| CTrans_utils.Self.SelfClassException class_name
-> (* FIXME(t21762295): we do not expect this to happen but it does *)
handle_frontend_failure ~print:true "Unexpected SelfClassException %a@\n" Typ.Name.pp
class_name
| exn when Config.keep_going
-> handle_frontend_failure ~print:true "Frontend error: %a@\nBacktrace:@\n%s" Exn.pp exn
(Exn.backtrace ())
let function_decl trans_unit_ctx tenv cfg cg func_decl block_data_opt = let function_decl trans_unit_ctx tenv cfg cg func_decl block_data_opt =
let captured_vars, outer_context_opt = let captured_vars, outer_context_opt =
@ -242,7 +252,9 @@ module CFrontend_decl_funct (T : CModule_type.CTranslation) : CModule_type.CFron
let open Clang_ast_t in let open Clang_ast_t in
(* each procedure has different scope: start names from id 0 *) (* each procedure has different scope: start names from id 0 *)
Ident.NameGenerator.reset () ; Ident.NameGenerator.reset () ;
let translate = translate_one_declaration trans_unit_ctx tenv cg cfg decl_trans_context in let translate dec =
translate_one_declaration trans_unit_ctx tenv cg cfg decl_trans_context dec
in
( if should_translate_decl trans_unit_ctx dec decl_trans_context then ( if should_translate_decl trans_unit_ctx dec decl_trans_context then
let dec_ptr = (Clang_ast_proj.get_decl_tuple dec).di_pointer in let dec_ptr = (Clang_ast_proj.get_decl_tuple dec).di_pointer in
match dec with match dec with
@ -336,7 +348,10 @@ module CFrontend_decl_funct (T : CModule_type.CTranslation) : CModule_type.CFron
in in
let method_decls, no_method_decls = List.partition_tf ~f:is_method_decl decl_list in let method_decls, no_method_decls = List.partition_tf ~f:is_method_decl decl_list in
List.iter ~f:translate no_method_decls ; List.iter ~f:translate no_method_decls ;
ignore (CType_decl.add_types_from_decl_to_tenv tenv dec) ; protect ~f:(fun () -> ignore (CType_decl.add_types_from_decl_to_tenv tenv dec))
~recover:Fn.id ~pp_context:(fun fmt () ->
F.fprintf fmt "Error adding types from decl '%a'"
(Pp.to_string ~f:Clang_ast_j.string_of_decl) dec ) ;
List.iter ~f:translate method_decls List.iter ~f:translate method_decls
| _ | _
-> () ) ; -> () ) ;

@ -204,6 +204,7 @@ codetoanalyze/cpp/errors/subtyping/dynamic_cast.cpp, dynamic__cast::wrongReferen
codetoanalyze/cpp/errors/subtyping/implicit_cast_with_const.cpp, implicit_cast_with_const::BaseDerefNPE, 2, NULL_DEREFERENCE, [start of procedure implicit_cast_with_const::BaseDerefNPE(),start of procedure Base,return from a call to implicit_cast_with_const::Base_Base,start of procedure implicit_cast_with_const::deref()] codetoanalyze/cpp/errors/subtyping/implicit_cast_with_const.cpp, implicit_cast_with_const::BaseDerefNPE, 2, NULL_DEREFERENCE, [start of procedure implicit_cast_with_const::BaseDerefNPE(),start of procedure Base,return from a call to implicit_cast_with_const::Base_Base,start of procedure implicit_cast_with_const::deref()]
codetoanalyze/cpp/errors/subtyping/implicit_cast_with_const.cpp, implicit_cast_with_const::DerivedDerefNPE, 2, NULL_DEREFERENCE, [start of procedure implicit_cast_with_const::DerivedDerefNPE(),start of procedure Derived,start of procedure Base,return from a call to implicit_cast_with_const::Base_Base,return from a call to implicit_cast_with_const::Derived_Derived,start of procedure implicit_cast_with_const::deref()] codetoanalyze/cpp/errors/subtyping/implicit_cast_with_const.cpp, implicit_cast_with_const::DerivedDerefNPE, 2, NULL_DEREFERENCE, [start of procedure implicit_cast_with_const::DerivedDerefNPE(),start of procedure Derived,start of procedure Base,return from a call to implicit_cast_with_const::Base_Base,return from a call to implicit_cast_with_const::Derived_Derived,start of procedure implicit_cast_with_const::deref()]
codetoanalyze/cpp/errors/subtyping/subtyping_check.cpp, B_setFG, 4, DIVIDE_BY_ZERO, [start of procedure setFG,start of procedure setF,return from a call to A_setF,Condition is true] codetoanalyze/cpp/errors/subtyping/subtyping_check.cpp, B_setFG, 4, DIVIDE_BY_ZERO, [start of procedure setFG,start of procedure setF,return from a call to A_setF,Condition is true]
codetoanalyze/cpp/errors/templates/dependent_parent.cpp, instantiate_class_bad, 2, DIVIDE_BY_ZERO, [start of procedure instantiate_class_bad(),start of procedure X,return from a call to X<int>_X,start of procedure x_y,start of procedure Y,start of procedure Z,return from a call to Z<int>_Z,return from a call to X<int>::Y_Y,start of procedure y,start of procedure z,return from a call to Z<int>_z,return from a call to X<int>::Y_y,return from a call to X<int>_x_y]
codetoanalyze/cpp/errors/templates/mangling.cpp, bad_integral_types_templates, 4, DIVIDE_BY_ZERO, [start of procedure bad_integral_types_templates(),start of procedure IntTemplate,return from a call to IntTemplate<0>_IntTemplate,start of procedure CharTemplate,return from a call to CharTemplate<99>_CharTemplate,start of procedure LongTemplate,return from a call to LongTemplate<1234567890>_LongTemplate] codetoanalyze/cpp/errors/templates/mangling.cpp, bad_integral_types_templates, 4, DIVIDE_BY_ZERO, [start of procedure bad_integral_types_templates(),start of procedure IntTemplate,return from a call to IntTemplate<0>_IntTemplate,start of procedure CharTemplate,return from a call to CharTemplate<99>_CharTemplate,start of procedure LongTemplate,return from a call to LongTemplate<1234567890>_LongTemplate]
codetoanalyze/cpp/errors/templates/mangling.cpp, bad_nullptr_templates, 2, DIVIDE_BY_ZERO, [start of procedure bad_nullptr_templates(),start of procedure NullPtrTemplate,return from a call to NullPtrTemplate<NullPtr>_NullPtrTemplate] codetoanalyze/cpp/errors/templates/mangling.cpp, bad_nullptr_templates, 2, DIVIDE_BY_ZERO, [start of procedure bad_nullptr_templates(),start of procedure NullPtrTemplate,return from a call to NullPtrTemplate<NullPtr>_NullPtrTemplate]
codetoanalyze/cpp/errors/templates/mangling.cpp, bad_packed_templates, 2, DIVIDE_BY_ZERO, [start of procedure bad_packed_templates(),start of procedure Tuple,return from a call to Tuple<Tuple<int>>_Tuple] codetoanalyze/cpp/errors/templates/mangling.cpp, bad_packed_templates, 2, DIVIDE_BY_ZERO, [start of procedure bad_packed_templates(),start of procedure Tuple,return from a call to Tuple<Tuple<int>>_Tuple]

@ -0,0 +1,35 @@
/*
* Copyright (c) 2017 - present Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
struct Y {
int y();
};
template <typename T>
struct X {
struct Y;
int x_y() {
struct Y y;
return y.y();
}
};
template <typename T>
struct Z {
int z() { return 3; };
};
template <typename T>
struct X<T>::Y : Z<T> {
int y() { return Y::z() - 3; }
};
void instantiate_class_bad() {
struct X<int> x;
int n = 1 / x.x_y();
}
Loading…
Cancel
Save