[C++] Store class template name without its template arguments

Summary:
Don't store redundant information in C++ template Type.Name.t.

New signature:
```
| CppClass (qual_name, template_args)
```

For example, for `std::shared_ptr<int>`, will look like this:
```
| CppClass (["std", "shared_ptr"], Template [int])
```
While it used to be:
```
| CppClass (["std", "shared_ptr<int>"], Template (["std", "shared_ptr"], [int]))
```

Reviewed By: jberdine, mbouaziz

Differential Revision: D4834512

fbshipit-source-id: cb1c570
master
Andrzej Kotulski 8 years ago committed by Facebook Github Bot
parent b3af2ad4b6
commit c1147710ba

@ -27,6 +27,14 @@ let strip_template_args quals => {
List.map f::no_template_name quals
};
let append_template_args_to_last quals ::args =>
switch quals {
| [last, _] when String.contains last '<' =>
failwith "expected qualified name without template args"
| [last, ...rest] => [last ^ args, ...rest]
| [] => failwith "expected non-empty qualified name"
};
let to_list = List.rev;
let to_rev_list = ident;

@ -39,6 +39,11 @@ let extract_last: t => option (string, t);
let strip_template_args: t => t;
/** append template arguments to the last qualifier. Fails if qualified name is empty or it already has
template args */
let append_template_args_to_last: t => args::string => t;
/** returns list of qualifers */
let to_list: t => list string;

@ -41,19 +41,10 @@ let create () => TypenameHash.create 1000;
/** Construct a struct type in a type environment */
let mk_struct
tenv
::default=?
::fields=?
::statics=?
::methods=?
::supers=?
::annots=?
::specialization=?
name => {
let mk_struct tenv ::default=? ::fields=? ::statics=? ::methods=? ::supers=? ::annots=? name => {
let struct_typ =
Typ.Struct.internal_mk_struct
::?default ::?fields ::?statics ::?methods ::?supers ::?annots ::?specialization ();
::?default ::?fields ::?statics ::?methods ::?supers ::?annots ();
TypenameHash.replace tenv name struct_typ;
struct_typ
};

@ -46,7 +46,6 @@ let mk_struct:
methods::list Typ.Procname.t? =>
supers::list Typ.Name.t? =>
annots::Annot.Item.t? =>
specialization::Typ.template_spec_info? =>
Typ.Name.t =>
Typ.Struct.t;

@ -146,7 +146,7 @@ module T = {
[@@deriving compare]
and template_spec_info =
| NoTemplate
| Template (QualifiedCppName.t, list (option t))
| Template (list (option t))
[@@deriving compare];
let equal_desc = [%compare.equal : desc];
let equal_quals = [%compare.equal : type_quals];
@ -183,26 +183,107 @@ let mk ::default=? ::quals=? desc :t => {
mk_aux ::?default ::?quals desc
};
let escape pe =>
if (Pp.equal_print_kind pe.Pp.kind Pp.HTML) {
Escape.escape_xml
} else {
ident
};
/** Pretty print a type with all the details, using the C syntax. */
let rec pp_full pe f typ => {
let pp_quals f {quals} => {
if (is_const quals) {
F.fprintf f " const "
};
if (is_restrict quals) {
F.fprintf f " __restrict "
};
if (is_volatile quals) {
F.fprintf f " volatile "
}
};
let pp_desc f {desc} =>
switch desc {
| Tstruct tname => F.fprintf f "%a" (pp_name_c_syntax pe) tname
| Tint ik => F.fprintf f "%s" (ikind_to_string ik)
| Tfloat fk => F.fprintf f "%s" (fkind_to_string fk)
| Tvoid => F.fprintf f "void"
| Tfun false => F.fprintf f "_fn_"
| Tfun true => F.fprintf f "_fn_noreturn_"
| Tptr ({desc: Tarray _ | Tfun _} as typ) pk =>
F.fprintf f "%a(%s)" (pp_full pe) typ (ptr_kind_string pk |> escape pe)
| Tptr typ pk => F.fprintf f "%a%s" (pp_full pe) typ (ptr_kind_string pk |> escape pe)
| Tarray typ static_len =>
let pp_array_static_len fmt => (
fun
| Some static_len => IntLit.pp fmt static_len
| None => F.fprintf fmt "_"
);
F.fprintf f "%a[%a]" (pp_full pe) typ pp_array_static_len static_len
};
F.fprintf f "%a%a" pp_desc typ pp_quals typ
}
and pp_name_c_syntax pe f =>
fun
| CStruct name
| CUnion name
| ObjcClass name
| ObjcProtocol name => F.fprintf f "%a" QualifiedCppName.pp name
| CppClass name template_spec =>
F.fprintf f "%a%a" QualifiedCppName.pp name (pp_template_spec_info pe) template_spec
| JavaClass name => F.fprintf f "%a" Mangled.pp name
and pp_template_spec_info pe f =>
fun
| NoTemplate => ()
| Template args => {
let pp_arg_opt f => (
fun
| Some typ => F.fprintf f "%a" (pp_full pe) typ
| None => F.fprintf f "_"
);
F.fprintf f "%s%a%s" (escape pe "<") (Pp.comma_seq pp_arg_opt) args (escape pe ">")
};
/** Pretty print a type. Do nothing by default. */
let pp pe f te =>
if Config.print_types {
pp_full pe f te
} else {
()
};
let to_string typ => {
let pp fmt => pp_full Pp.text fmt typ;
F.asprintf "%t" pp
};
module Name = {
type t = name [@@deriving compare];
let equal = [%compare.equal : t];
let name =
fun
| CStruct name
| CUnion name
| CppClass name _
| ObjcClass name
| ObjcProtocol name => QualifiedCppName.to_qual_string name
| JavaClass name => Mangled.to_string name;
let qual_name =
fun
| CStruct name
| CUnion name
| CppClass name _
| ObjcClass name
| ObjcProtocol name => name
| CppClass name templ_args => {
let template_suffix = F.asprintf "%a" (pp_template_spec_info Pp.text) templ_args;
QualifiedCppName.append_template_args_to_last name args::template_suffix
}
| JavaClass _ => QualifiedCppName.empty;
let to_string tname => {
let name n =>
switch n {
| CStruct _
| CUnion _
| CppClass _ _
| ObjcClass _
| ObjcProtocol _ => qual_name n |> QualifiedCppName.to_qual_string
| JavaClass name => Mangled.to_string name
};
let pp fmt tname => {
let prefix =
fun
| CStruct _ => "struct"
@ -211,9 +292,9 @@ module Name = {
| JavaClass _
| ObjcClass _ => "class"
| ObjcProtocol _ => "protocol";
prefix tname ^ " " ^ name tname
F.fprintf fmt "%s %a" (prefix tname) (pp_name_c_syntax Pp.text) tname
};
let pp f typename => F.fprintf f "%s" (to_string typename);
let to_string = F.asprintf "%a" pp;
let is_class =
fun
| CppClass _ _
@ -283,61 +364,6 @@ module Map = Caml.Map.Make T;
module Tbl = Hashtbl.Make T;
/** Pretty print a type with all the details, using the C syntax. */
let rec pp_full pe f typ => {
let pp_quals f {quals} => {
if (is_const quals) {
F.fprintf f " const "
};
if (is_restrict quals) {
F.fprintf f " __restrict "
};
if (is_volatile quals) {
F.fprintf f " volatile "
}
};
let pp_desc f {desc} =>
switch desc {
| Tstruct tname =>
if (Pp.equal_print_kind pe.Pp.kind Pp.HTML) {
F.fprintf f "%s" (Name.name tname |> Escape.escape_xml)
} else {
F.fprintf f "%s" (Name.name tname)
}
| Tint ik => F.fprintf f "%s" (ikind_to_string ik)
| Tfloat fk => F.fprintf f "%s" (fkind_to_string fk)
| Tvoid => F.fprintf f "void"
| Tfun false => F.fprintf f "_fn_"
| Tfun true => F.fprintf f "_fn_noreturn_"
| Tptr ({desc: Tarray _ | Tfun _} as typ) pk =>
F.fprintf f "%a(%s)" (pp_full pe) typ (ptr_kind_string pk)
| Tptr typ pk => F.fprintf f "%a%s" (pp_full pe) typ (ptr_kind_string pk)
| Tarray typ static_len =>
let pp_array_static_len fmt => (
fun
| Some static_len => IntLit.pp fmt static_len
| None => F.fprintf fmt "_"
);
F.fprintf f "%a[%a]" (pp_full pe) typ pp_array_static_len static_len
};
F.fprintf f "%a%a" pp_desc typ pp_quals typ
};
/** Pretty print a type. Do nothing by default. */
let pp pe f te =>
if Config.print_types {
pp_full pe f te
} else {
()
};
let to_string typ => {
let pp fmt => pp_full Pp.text fmt typ;
F.asprintf "%t" pp
};
/** dump a type with all the details. */
let d_full (t: t) => L.add_print_action (L.PTtyp_full, Obj.repr t);
@ -1016,8 +1042,7 @@ module Struct = {
statics: fields, /** static fields */
supers: list Name.t, /** superclasses */
methods: list Procname.t, /** methods defined */
annots: Annot.Item.t, /** annotations */
specialization: template_spec_info /** template specialization */
annots: Annot.Item.t /** annotations */
};
type lookup = Name.t => option t;
let pp pe name f {fields, supers, methods, annots} =>
@ -1044,23 +1069,8 @@ module Struct = {
} else {
F.fprintf f "%a" Name.pp name
};
let internal_mk_struct
::default=?
::fields=?
::statics=?
::methods=?
::supers=?
::annots=?
::specialization=?
() => {
let default_ = {
fields: [],
statics: [],
methods: [],
supers: [],
annots: Annot.Item.empty,
specialization: NoTemplate
};
let internal_mk_struct ::default=? ::fields=? ::statics=? ::methods=? ::supers=? ::annots=? () => {
let default_ = {fields: [], statics: [], methods: [], supers: [], annots: Annot.Item.empty};
let mk_struct_
::default=default_
::fields=default.fields
@ -1068,16 +1078,14 @@ module Struct = {
::methods=default.methods
::supers=default.supers
::annots=default.annots
::specialization=default.specialization
() => {
fields,
statics,
methods,
supers,
annots,
specialization
annots
};
mk_struct_ ::?default ::?fields ::?statics ::?methods ::?supers ::?annots ::?specialization ()
mk_struct_ ::?default ::?fields ::?statics ::?methods ::?supers ::?annots ()
};
/** the element typ of the final extensible array in the given typ, if any */

@ -85,6 +85,7 @@ let is_restrict: type_quals => bool;
let is_volatile: type_quals => bool;
/** types for sil (structured) expressions */
/** types for sil (structured) expressions */
@ -101,6 +102,9 @@ and desc =
and name =
| CStruct QualifiedCppName.t
| CUnion QualifiedCppName.t
/* qualified name does NOT contain template arguments of the class. It will contain template
args of its parent classes, for example: MyClass<int>::InnerClass<int> will store
"MyClass<int>", "InnerClass" */
| CppClass QualifiedCppName.t template_spec_info
| JavaClass Mangled.t
| ObjcClass QualifiedCppName.t
@ -108,7 +112,7 @@ and name =
[@@deriving compare]
and template_spec_info =
| NoTemplate
| Template (QualifiedCppName.t, list (option t))
| Template (list (option t))
[@@deriving compare];
@ -485,8 +489,7 @@ module Struct: {
statics: fields, /** static fields */
supers: list Name.t, /** supers */
methods: list Procname.t, /** methods defined */
annots: Annot.Item.t, /** annotations */
specialization: template_spec_info /** template specialization */
annots: Annot.Item.t /** annotations */
};
type lookup = Name.t => option t;
@ -501,7 +504,6 @@ module Struct: {
methods::list Procname.t? =>
supers::list Name.t? =>
annots::Annot.Item.t? =>
specialization::template_spec_info? =>
unit =>
t;

@ -32,7 +32,6 @@ let rec get_mangled_method_name function_decl_info method_decl_info =
let get_template_info tenv (fdi : Clang_ast_t.function_decl_info) : Typ.template_spec_info =
match fdi.fdi_template_specialization with
| Some spec_info -> Typ.Template (
QualifiedCppName.empty,
List.map spec_info.tsi_specialization_args ~f:(function
| `Type qual_type -> Some (CType_decl.qual_type_to_sil_type tenv qual_type)
| _ -> None))

@ -116,39 +116,33 @@ and get_record_custom_type tenv definition_decl =
Option.map ~f:(qual_type_to_sil_type tenv) (get_translate_as_friend_decl decl_list)
| _ -> None
and get_template_specialization tenv = function
| Clang_ast_t.ClassTemplateSpecializationDecl (_, _, _, _, _, _, _, _, spec_info) ->
let tname = match CAst_utils.get_decl spec_info.tsi_template_decl with
| Some decl -> get_class_template_name decl
| None -> assert false in
let args_in_sil = List.map spec_info.tsi_specialization_args ~f:(function
| `Type qual_type -> Some (qual_type_to_sil_type tenv qual_type)
| _ -> None) in
Typ.Template (tname, args_in_sil)
| _ -> Typ.NoTemplate
(* We need to take the name out of the type as the struct can be anonymous
If tenv is not passed, then template instantiaion information may be incorrect,
as it defaults to Typ.NoTemplate *)
and get_record_typename ?tenv decl =
let open Clang_ast_t in
match decl with
| RecordDecl (_, name_info, opt_type, _, _, _, _) ->
match decl, tenv with
| RecordDecl (_, name_info, opt_type, _, _, _, _), _ ->
CAst_utils.get_qualified_name name_info |> create_c_record_typename opt_type
| CXXRecordDecl (_, name_info, _, _, _, _, _, _)
| ClassTemplateSpecializationDecl (_, name_info, _, _, _, _, _, _, _) ->
| ClassTemplateSpecializationDecl (_, _, _, _, _, _, _, _, spec_info), Some tenv ->
let tname = match CAst_utils.get_decl spec_info.tsi_template_decl with
| Some dec -> get_class_template_name dec
| None -> assert false in
let args_in_sil = List.map spec_info.tsi_specialization_args ~f:(function
| `Type qual_type -> Some (qual_type_to_sil_type tenv qual_type)
| _ -> None) in
Typ.Name.Cpp.from_qual_name (Typ.Template args_in_sil) tname
| CXXRecordDecl (_, name_info, _, _, _, _, _, _), _
| ClassTemplateSpecializationDecl (_, name_info, _, _, _, _, _, _, _), _ ->
(* we use Typ.CppClass for C++ because we expect Typ.CppClass from *)
(* types that have methods. And in C++ struct/class/union can have methods *)
let qual_name = CAst_utils.get_qualified_name name_info in
let templ_info = match tenv with
| Some t -> get_template_specialization t decl
| None -> Typ.NoTemplate in
Typ.Name.Cpp.from_qual_name templ_info qual_name
| ObjCInterfaceDecl (_, name_info, _, _, _)
| ObjCImplementationDecl (_, name_info, _, _, _)
| ObjCProtocolDecl (_, name_info, _, _, _)
| ObjCCategoryDecl (_, name_info, _, _, _)
| ObjCCategoryImplDecl (_, name_info, _, _, _) ->
Typ.Name.Cpp.from_qual_name Typ.NoTemplate (CAst_utils.get_qualified_name name_info)
| ObjCInterfaceDecl (_, name_info, _, _, _), _
| ObjCImplementationDecl (_, name_info, _, _, _), _
| ObjCProtocolDecl (_, name_info, _, _, _), _
| ObjCCategoryDecl (_, name_info, _, _, _), _
| ObjCCategoryImplDecl (_, name_info, _, _, _), _ ->
CAst_utils.get_qualified_name name_info |> Typ.Name.Objc.from_qual_name
| _ -> assert false
@ -184,8 +178,7 @@ and get_record_struct_type tenv definition_decl : Typ.desc =
let statics = [] in (* Note: We treat static field same as global variables *)
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 specialization = get_template_specialization tenv definition_decl in
Tenv.mk_struct tenv ~fields ~statics ~methods ~supers ~annots ~specialization
Tenv.mk_struct tenv ~fields ~statics ~methods ~supers ~annots
sil_typename |> ignore;
CAst_utils.update_sil_types_map type_ptr sil_desc;
sil_desc

@ -1,13 +1,13 @@
/* @generated */
digraph iCFG {
"main.fad58de7366495db4650cfefac2fcd61_1" [label="1: Start main\nFormals: \nLocals: s:std::basic_string<b7ca98c5140c72c> x:int* \n DECLARE_LOCALS(&return,&s,&x); [line 17]\n " color=yellow style=filled]
"main.fad58de7366495db4650cfefac2fcd61_1" [label="1: Start main\nFormals: \nLocals: s:std::basic_string<char,std::char_traits<char>,std::allocator<char>> x:int* \n DECLARE_LOCALS(&return,&s,&x); [line 17]\n " color=yellow style=filled]
"main.fad58de7366495db4650cfefac2fcd61_1" -> "main.fad58de7366495db4650cfefac2fcd61_7" ;
"main.fad58de7366495db4650cfefac2fcd61_2" [label="2: Exit main \n " color=yellow style=filled]
"main.fad58de7366495db4650cfefac2fcd61_3" [label="3: DeclStmt \n _fun_std::basic_string<b7ca98c5140c72c>_basic_string(&s:std::basic_string<b7ca98c5140c72c>*,\"1234\":char const *) [line 22]\n " shape="box"]
"main.fad58de7366495db4650cfefac2fcd61_3" [label="3: DeclStmt \n _fun_std::basic_string<char,std::char_traits<char>,std::allocator<char>>_basic_string(&s:std::basic_string<char,std::char_traits<char>,std::allocator<char>>*,\"1234\":char const *) [line 22]\n " shape="box"]
"main.fad58de7366495db4650cfefac2fcd61_3" -> "main.fad58de7366495db4650cfefac2fcd61_2" ;

@ -1,13 +1,13 @@
/* @generated */
digraph iCFG {
"main.fad58de7366495db4650cfefac2fcd61_1" [label="1: Start main\nFormals: \nLocals: s:std::basic_string<b7ca98c5140c72c> x:int* \n DECLARE_LOCALS(&return,&s,&x); [line 17]\n " color=yellow style=filled]
"main.fad58de7366495db4650cfefac2fcd61_1" [label="1: Start main\nFormals: \nLocals: s:std::basic_string<char,std::char_traits<char>,std::allocator<char>> x:int* \n DECLARE_LOCALS(&return,&s,&x); [line 17]\n " color=yellow style=filled]
"main.fad58de7366495db4650cfefac2fcd61_1" -> "main.fad58de7366495db4650cfefac2fcd61_7" ;
"main.fad58de7366495db4650cfefac2fcd61_2" [label="2: Exit main \n " color=yellow style=filled]
"main.fad58de7366495db4650cfefac2fcd61_3" [label="3: DeclStmt \n _fun_std::basic_string<b7ca98c5140c72c>_basic_string(&s:std::basic_string<b7ca98c5140c72c>*,\"1234\":char const *) [line 22]\n " shape="box"]
"main.fad58de7366495db4650cfefac2fcd61_3" [label="3: DeclStmt \n _fun_std::basic_string<char,std::char_traits<char>,std::allocator<char>>_basic_string(&s:std::basic_string<char,std::char_traits<char>,std::allocator<char>>*,\"1234\":char const *) [line 22]\n " shape="box"]
"main.fad58de7366495db4650cfefac2fcd61_3" -> "main.fad58de7366495db4650cfefac2fcd61_2" ;

@ -1,13 +1,13 @@
/* @generated */
digraph iCFG {
"main.fad58de7366495db4650cfefac2fcd61_1" [label="1: Start main\nFormals: \nLocals: s:std::basic_string<b7ca98c5140c72c> x:int* \n DECLARE_LOCALS(&return,&s,&x); [line 17]\n " color=yellow style=filled]
"main.fad58de7366495db4650cfefac2fcd61_1" [label="1: Start main\nFormals: \nLocals: s:std::basic_string<char,std::char_traits<char>,std::allocator<char>> x:int* \n DECLARE_LOCALS(&return,&s,&x); [line 17]\n " color=yellow style=filled]
"main.fad58de7366495db4650cfefac2fcd61_1" -> "main.fad58de7366495db4650cfefac2fcd61_7" ;
"main.fad58de7366495db4650cfefac2fcd61_2" [label="2: Exit main \n " color=yellow style=filled]
"main.fad58de7366495db4650cfefac2fcd61_3" [label="3: DeclStmt \n _fun_std::basic_string<b7ca98c5140c72c>_basic_string(&s:std::basic_string<b7ca98c5140c72c>*,\"1234\":char const *) [line 22]\n " shape="box"]
"main.fad58de7366495db4650cfefac2fcd61_3" [label="3: DeclStmt \n _fun_std::basic_string<char,std::char_traits<char>,std::allocator<char>>_basic_string(&s:std::basic_string<char,std::char_traits<char>,std::allocator<char>>*,\"1234\":char const *) [line 22]\n " shape="box"]
"main.fad58de7366495db4650cfefac2fcd61_3" -> "main.fad58de7366495db4650cfefac2fcd61_2" ;

@ -1,13 +1,13 @@
/* @generated */
digraph iCFG {
"main.fad58de7366495db4650cfefac2fcd61_1" [label="1: Start main\nFormals: \nLocals: s:std::basic_string<b7ca98c5140c72c> x:int* \n DECLARE_LOCALS(&return,&s,&x); [line 17]\n " color=yellow style=filled]
"main.fad58de7366495db4650cfefac2fcd61_1" [label="1: Start main\nFormals: \nLocals: s:std::basic_string<char,std::char_traits<char>,std::allocator<char>> x:int* \n DECLARE_LOCALS(&return,&s,&x); [line 17]\n " color=yellow style=filled]
"main.fad58de7366495db4650cfefac2fcd61_1" -> "main.fad58de7366495db4650cfefac2fcd61_7" ;
"main.fad58de7366495db4650cfefac2fcd61_2" [label="2: Exit main \n " color=yellow style=filled]
"main.fad58de7366495db4650cfefac2fcd61_3" [label="3: DeclStmt \n _fun_std::basic_string<b7ca98c5140c72c>_basic_string(&s:std::basic_string<b7ca98c5140c72c>*,\"1234\":char const *) [line 22]\n " shape="box"]
"main.fad58de7366495db4650cfefac2fcd61_3" [label="3: DeclStmt \n _fun_std::basic_string<char,std::char_traits<char>,std::allocator<char>>_basic_string(&s:std::basic_string<char,std::char_traits<char>,std::allocator<char>>*,\"1234\":char const *) [line 22]\n " shape="box"]
"main.fad58de7366495db4650cfefac2fcd61_3" -> "main.fad58de7366495db4650cfefac2fcd61_2" ;

@ -96,40 +96,40 @@ digraph iCFG {
"div0#A#(_ZN1A4div0Ev).1a6f91584aabeebe049737afeb476378_3" -> "div0#A#(_ZN1A4div0Ev).1a6f91584aabeebe049737afeb476378_2" ;
"B#B<A>#{_ZN1BI1AEC1Ev|constexpr}.37a0dc804dbb70abe9c0cba5d0d4b75d_1" [label="1: Start B<A>_B\nFormals: this:B<A>*\nLocals: \n DECLARE_LOCALS(&return); [line 15]\n " color=yellow style=filled]
"B#B<int>#{_ZN1BIiEC1Ev|constexpr}.0a6e40da0e7d400cfcd0dfa1df7ad995_1" [label="1: Start B<int>_B\nFormals: this:B<int>*\nLocals: \n DECLARE_LOCALS(&return); [line 15]\n " color=yellow style=filled]
"B#B<A>#{_ZN1BI1AEC1Ev|constexpr}.37a0dc804dbb70abe9c0cba5d0d4b75d_1" -> "B#B<A>#{_ZN1BI1AEC1Ev|constexpr}.37a0dc804dbb70abe9c0cba5d0d4b75d_2" ;
"B#B<A>#{_ZN1BI1AEC1Ev|constexpr}.37a0dc804dbb70abe9c0cba5d0d4b75d_2" [label="2: Exit B<A>_B \n " color=yellow style=filled]
"B#B<int>#{_ZN1BIiEC1Ev|constexpr}.0a6e40da0e7d400cfcd0dfa1df7ad995_1" -> "B#B<int>#{_ZN1BIiEC1Ev|constexpr}.0a6e40da0e7d400cfcd0dfa1df7ad995_2" ;
"B#B<int>#{_ZN1BIiEC1Ev|constexpr}.0a6e40da0e7d400cfcd0dfa1df7ad995_2" [label="2: Exit B<int>_B \n " color=yellow style=filled]
"div0#B<A>#(_ZN1BI1AE4div0Ev).95154c4eecaa5aa2388f6884c1f2eb1f_1" [label="1: Start B<A>_div0\nFormals: this:B<A>*\nLocals: \n DECLARE_LOCALS(&return); [line 16]\n " color=yellow style=filled]
"div0#B<int>#(_ZN1BIiE4div0Ev).7928d23b80a07771917a21f2f65199b6_1" [label="1: Start B<int>_div0\nFormals: this:B<int>*\nLocals: \n DECLARE_LOCALS(&return); [line 16]\n " color=yellow style=filled]
"div0#B<A>#(_ZN1BI1AE4div0Ev).95154c4eecaa5aa2388f6884c1f2eb1f_1" -> "div0#B<A>#(_ZN1BI1AE4div0Ev).95154c4eecaa5aa2388f6884c1f2eb1f_3" ;
"div0#B<A>#(_ZN1BI1AE4div0Ev).95154c4eecaa5aa2388f6884c1f2eb1f_2" [label="2: Exit B<A>_div0 \n " color=yellow style=filled]
"div0#B<int>#(_ZN1BIiE4div0Ev).7928d23b80a07771917a21f2f65199b6_1" -> "div0#B<int>#(_ZN1BIiE4div0Ev).7928d23b80a07771917a21f2f65199b6_3" ;
"div0#B<int>#(_ZN1BIiE4div0Ev).7928d23b80a07771917a21f2f65199b6_2" [label="2: Exit B<int>_div0 \n " color=yellow style=filled]
"div0#B<A>#(_ZN1BI1AE4div0Ev).95154c4eecaa5aa2388f6884c1f2eb1f_3" [label="3: Return Stmt \n *&return:int=(1 / 0) [line 16]\n " shape="box"]
"div0#B<int>#(_ZN1BIiE4div0Ev).7928d23b80a07771917a21f2f65199b6_3" [label="3: Return Stmt \n *&return:int=(1 / 0) [line 16]\n " shape="box"]
"div0#B<A>#(_ZN1BI1AE4div0Ev).95154c4eecaa5aa2388f6884c1f2eb1f_3" -> "div0#B<A>#(_ZN1BI1AE4div0Ev).95154c4eecaa5aa2388f6884c1f2eb1f_2" ;
"B#B<int>#{_ZN1BIiEC1Ev|constexpr}.0a6e40da0e7d400cfcd0dfa1df7ad995_1" [label="1: Start B<int>_B\nFormals: this:B<int>*\nLocals: \n DECLARE_LOCALS(&return); [line 15]\n " color=yellow style=filled]
"div0#B<int>#(_ZN1BIiE4div0Ev).7928d23b80a07771917a21f2f65199b6_3" -> "div0#B<int>#(_ZN1BIiE4div0Ev).7928d23b80a07771917a21f2f65199b6_2" ;
"B#B<A>#{_ZN1BI1AEC1Ev|constexpr}.37a0dc804dbb70abe9c0cba5d0d4b75d_1" [label="1: Start B<A>_B\nFormals: this:B<A>*\nLocals: \n DECLARE_LOCALS(&return); [line 15]\n " color=yellow style=filled]
"B#B<int>#{_ZN1BIiEC1Ev|constexpr}.0a6e40da0e7d400cfcd0dfa1df7ad995_1" -> "B#B<int>#{_ZN1BIiEC1Ev|constexpr}.0a6e40da0e7d400cfcd0dfa1df7ad995_2" ;
"B#B<int>#{_ZN1BIiEC1Ev|constexpr}.0a6e40da0e7d400cfcd0dfa1df7ad995_2" [label="2: Exit B<int>_B \n " color=yellow style=filled]
"B#B<A>#{_ZN1BI1AEC1Ev|constexpr}.37a0dc804dbb70abe9c0cba5d0d4b75d_1" -> "B#B<A>#{_ZN1BI1AEC1Ev|constexpr}.37a0dc804dbb70abe9c0cba5d0d4b75d_2" ;
"B#B<A>#{_ZN1BI1AEC1Ev|constexpr}.37a0dc804dbb70abe9c0cba5d0d4b75d_2" [label="2: Exit B<A>_B \n " color=yellow style=filled]
"div0#B<int>#(_ZN1BIiE4div0Ev).7928d23b80a07771917a21f2f65199b6_1" [label="1: Start B<int>_div0\nFormals: this:B<int>*\nLocals: \n DECLARE_LOCALS(&return); [line 16]\n " color=yellow style=filled]
"div0#B<A>#(_ZN1BI1AE4div0Ev).95154c4eecaa5aa2388f6884c1f2eb1f_1" [label="1: Start B<A>_div0\nFormals: this:B<A>*\nLocals: \n DECLARE_LOCALS(&return); [line 16]\n " color=yellow style=filled]
"div0#B<int>#(_ZN1BIiE4div0Ev).7928d23b80a07771917a21f2f65199b6_1" -> "div0#B<int>#(_ZN1BIiE4div0Ev).7928d23b80a07771917a21f2f65199b6_3" ;
"div0#B<int>#(_ZN1BIiE4div0Ev).7928d23b80a07771917a21f2f65199b6_2" [label="2: Exit B<int>_div0 \n " color=yellow style=filled]
"div0#B<A>#(_ZN1BI1AE4div0Ev).95154c4eecaa5aa2388f6884c1f2eb1f_1" -> "div0#B<A>#(_ZN1BI1AE4div0Ev).95154c4eecaa5aa2388f6884c1f2eb1f_3" ;
"div0#B<A>#(_ZN1BI1AE4div0Ev).95154c4eecaa5aa2388f6884c1f2eb1f_2" [label="2: Exit B<A>_div0 \n " color=yellow style=filled]
"div0#B<int>#(_ZN1BIiE4div0Ev).7928d23b80a07771917a21f2f65199b6_3" [label="3: Return Stmt \n *&return:int=(1 / 0) [line 16]\n " shape="box"]
"div0#B<A>#(_ZN1BI1AE4div0Ev).95154c4eecaa5aa2388f6884c1f2eb1f_3" [label="3: Return Stmt \n *&return:int=(1 / 0) [line 16]\n " shape="box"]
"div0#B<int>#(_ZN1BIiE4div0Ev).7928d23b80a07771917a21f2f65199b6_3" -> "div0#B<int>#(_ZN1BIiE4div0Ev).7928d23b80a07771917a21f2f65199b6_2" ;
"div0#B<A>#(_ZN1BI1AE4div0Ev).95154c4eecaa5aa2388f6884c1f2eb1f_3" -> "div0#B<A>#(_ZN1BI1AE4div0Ev).95154c4eecaa5aa2388f6884c1f2eb1f_2" ;
}

Loading…
Cancel
Save