[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_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 ml_loc = string * int * int * int

@ -222,17 +222,17 @@ and get_record_struct_type tenv definition_decl : Typ.desc =
| Some _
-> sil_desc (* just reuse what is already in tenv *)
| 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 =
if CTrans_models.is_objc_memory_model_controlled (Typ.Name.name sil_typename) then
[Typ.Struct.objc_ref_counter_field]
else []
in
let annots =
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 (
if is_translatable_definition then (
CAst_utils.update_sil_types_map type_ptr sil_desc ;
let non_statics = get_struct_fields tenv definition_decl 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
(* C++ methods are not put into tenv (info isn't used) *)
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 ;
CAst_utils.update_sil_types_map type_ptr sil_desc ;
sil_desc )

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

@ -8,11 +8,35 @@
*)
open! IStd
module F = Format
(** Translate declarations **)
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
let model_exists procname = Specs.summary_exists_in_models procname && not Config.models_mode
@ -21,52 +45,38 @@ module CFrontend_decl_funct (T : CModule_type.CTranslation) : CModule_type.CFron
body has_return_param is_objc_method outer_context_opt extra_instrs =
L.(debug Capture Verbose)
"@\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 ;
CMethod_trans.create_external_procdesc cfg procname is_objc_method None ;
(if print then L.internal_error else L.(debug Capture Quiet))
("Aborting translation of method '%a':@\n" ^^ fmt) Typ.Procname.pp procname
CMethod_trans.create_external_procdesc cfg procname is_objc_method None
in
try
let pp_context fmt () =
F.fprintf fmt "Aborting translation of method '%a'" Typ.Procname.pp procname
in
let f () =
match Cfg.find_proc_desc_from_name cfg procname with
| Some procdesc
-> if Procdesc.is_defined procdesc && not (model_exists procname) then
let vars_to_destroy = CTrans_utils.Scope.compute_vars_to_destroy body in
let context =
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
in
let start_node = Procdesc.get_start_node procdesc in
let exit_node = Procdesc.get_exit_node procdesc in
L.(debug Capture Verbose)
"@\n@\n>>---------- Start translating body of function: '%s' ---------<<@\n@."
(Typ.Procname.to_string procname) ;
let meth_body_nodes =
T.instructions_trans context body extra_instrs exit_node ~is_destructor_wrapper
in
let proc_attributes = Procdesc.get_attributes procdesc in
Procdesc.Node.add_locals_ret_declaration start_node proc_attributes
(Procdesc.get_locals procdesc) ;
Procdesc.node_set_succs_exn procdesc start_node meth_body_nodes [] ;
Cg.add_defined_node (CContext.get_cg context) (Procdesc.get_proc_name procdesc)
| None
| Some procdesc when Procdesc.is_defined procdesc && not (model_exists procname)
-> let vars_to_destroy = CTrans_utils.Scope.compute_vars_to_destroy body in
let context =
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
in
let start_node = Procdesc.get_start_node procdesc in
let exit_node = Procdesc.get_exit_node procdesc in
L.(debug Capture Verbose)
"@\n@\n>>---------- Start translating body of function: '%s' ---------<<@\n@."
(Typ.Procname.to_string procname) ;
let meth_body_nodes =
T.instructions_trans context body extra_instrs exit_node ~is_destructor_wrapper
in
let proc_attributes = Procdesc.get_attributes procdesc in
Procdesc.Node.add_locals_ret_declaration start_node proc_attributes
(Procdesc.get_locals procdesc) ;
Procdesc.node_set_succs_exn procdesc start_node meth_body_nodes [] ;
Cg.add_defined_node (CContext.get_cg context) (Procdesc.get_proc_name procdesc)
| _
-> ()
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
-> 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 ())
in
protect ~f ~recover ~pp_context
let function_decl trans_unit_ctx tenv cfg cg func_decl block_data_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
(* each procedure has different scope: start names from id 0 *)
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
let dec_ptr = (Clang_ast_proj.get_decl_tuple dec).di_pointer in
match dec with
@ -336,7 +348,10 @@ module CFrontend_decl_funct (T : CModule_type.CTranslation) : CModule_type.CFron
in
let method_decls, no_method_decls = List.partition_tf ~f:is_method_decl decl_list in
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
| _
-> () ) ;

@ -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::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/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_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]

@ -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