ipa-prop.c (type_change_info): New fields offset, object, known_current_type and multiple_types_encountered.
2011-11-03 Martin Jambor <mjambor@suse.cz> * ipa-prop.c (type_change_info): New fields offset, object, known_current_type and multiple_types_encountered. (extr_type_from_vtbl_ptr_store): New function. (check_stmt_for_type_change): Use it, set multiple_types_encountered if the result is different from the previous one. (detect_type_change): Renamed to detect_type_change_1. New parameter comp_type. Set up new fields in tci, build known type jump functions if the new type can be identified. (detect_type_change): New function. * tree.h (DECL_CONTEXT): Comment new use. * testsuite/g++.dg/ipa/devirt-c-1.C: Add dump scans. * testsuite/g++.dg/ipa/devirt-c-2.C: Likewise. * testsuite/g++.dg/ipa/devirt-c-7.C: New test. * testsuite/g++.dg/ipa/devirt-c-8.C: Likewise. From-SVN: r180825
This commit is contained in:
parent
969d578c2d
commit
290ebcb77f
8 changed files with 326 additions and 33 deletions
|
@ -1,3 +1,16 @@
|
||||||
|
2011-11-03 Martin Jambor <mjambor@suse.cz>
|
||||||
|
|
||||||
|
* ipa-prop.c (type_change_info): New fields offset, object,
|
||||||
|
known_current_type and multiple_types_encountered.
|
||||||
|
(extr_type_from_vtbl_ptr_store): New function.
|
||||||
|
(check_stmt_for_type_change): Use it, set multiple_types_encountered if
|
||||||
|
the result is different from the previous one.
|
||||||
|
(detect_type_change): Renamed to detect_type_change_1. New parameter
|
||||||
|
comp_type. Set up new fields in tci, build known type jump
|
||||||
|
functions if the new type can be identified.
|
||||||
|
(detect_type_change): New function.
|
||||||
|
* tree.h (DECL_CONTEXT): Comment new use.
|
||||||
|
|
||||||
2011-11-03 Richard Guenther <rguenther@suse.de>
|
2011-11-03 Richard Guenther <rguenther@suse.de>
|
||||||
|
|
||||||
PR lto/48217
|
PR lto/48217
|
||||||
|
|
152
gcc/ipa-prop.c
152
gcc/ipa-prop.c
|
@ -271,8 +271,20 @@ ipa_print_all_jump_functions (FILE *f)
|
||||||
|
|
||||||
struct type_change_info
|
struct type_change_info
|
||||||
{
|
{
|
||||||
|
/* Offset into the object where there is the virtual method pointer we are
|
||||||
|
looking for. */
|
||||||
|
HOST_WIDE_INT offset;
|
||||||
|
/* The declaration or SSA_NAME pointer of the base that we are checking for
|
||||||
|
type change. */
|
||||||
|
tree object;
|
||||||
|
/* If we actually can tell the type that the object has changed to, it is
|
||||||
|
stored in this field. Otherwise it remains NULL_TREE. */
|
||||||
|
tree known_current_type;
|
||||||
/* Set to true if dynamic type change has been detected. */
|
/* Set to true if dynamic type change has been detected. */
|
||||||
bool type_maybe_changed;
|
bool type_maybe_changed;
|
||||||
|
/* Set to true if multiple types have been encountered. known_current_type
|
||||||
|
must be disregarded in that case. */
|
||||||
|
bool multiple_types_encountered;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Return true if STMT can modify a virtual method table pointer.
|
/* Return true if STMT can modify a virtual method table pointer.
|
||||||
|
@ -338,6 +350,50 @@ stmt_may_be_vtbl_ptr_store (gimple stmt)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* If STMT can be proved to be an assignment to the virtual method table
|
||||||
|
pointer of ANALYZED_OBJ and the type associated with the new table
|
||||||
|
identified, return the type. Otherwise return NULL_TREE. */
|
||||||
|
|
||||||
|
static tree
|
||||||
|
extr_type_from_vtbl_ptr_store (gimple stmt, struct type_change_info *tci)
|
||||||
|
{
|
||||||
|
HOST_WIDE_INT offset, size, max_size;
|
||||||
|
tree lhs, rhs, base;
|
||||||
|
|
||||||
|
if (!gimple_assign_single_p (stmt))
|
||||||
|
return NULL_TREE;
|
||||||
|
|
||||||
|
lhs = gimple_assign_lhs (stmt);
|
||||||
|
rhs = gimple_assign_rhs1 (stmt);
|
||||||
|
if (TREE_CODE (lhs) != COMPONENT_REF
|
||||||
|
|| !DECL_VIRTUAL_P (TREE_OPERAND (lhs, 1))
|
||||||
|
|| TREE_CODE (rhs) != ADDR_EXPR)
|
||||||
|
return NULL_TREE;
|
||||||
|
rhs = get_base_address (TREE_OPERAND (rhs, 0));
|
||||||
|
if (!rhs
|
||||||
|
|| TREE_CODE (rhs) != VAR_DECL
|
||||||
|
|| !DECL_VIRTUAL_P (rhs))
|
||||||
|
return NULL_TREE;
|
||||||
|
|
||||||
|
base = get_ref_base_and_extent (lhs, &offset, &size, &max_size);
|
||||||
|
if (offset != tci->offset
|
||||||
|
|| size != POINTER_SIZE
|
||||||
|
|| max_size != POINTER_SIZE)
|
||||||
|
return NULL_TREE;
|
||||||
|
if (TREE_CODE (base) == MEM_REF)
|
||||||
|
{
|
||||||
|
if (TREE_CODE (tci->object) != MEM_REF
|
||||||
|
|| TREE_OPERAND (tci->object, 0) != TREE_OPERAND (base, 0)
|
||||||
|
|| !tree_int_cst_equal (TREE_OPERAND (tci->object, 1),
|
||||||
|
TREE_OPERAND (base, 1)))
|
||||||
|
return NULL_TREE;
|
||||||
|
}
|
||||||
|
else if (tci->object != base)
|
||||||
|
return NULL_TREE;
|
||||||
|
|
||||||
|
return DECL_CONTEXT (rhs);
|
||||||
|
}
|
||||||
|
|
||||||
/* Callback of walk_aliased_vdefs and a helper function for
|
/* Callback of walk_aliased_vdefs and a helper function for
|
||||||
detect_type_change to check whether a particular statement may modify
|
detect_type_change to check whether a particular statement may modify
|
||||||
the virtual table pointer, and if possible also determine the new type of
|
the virtual table pointer, and if possible also determine the new type of
|
||||||
|
@ -352,6 +408,12 @@ check_stmt_for_type_change (ao_ref *ao ATTRIBUTE_UNUSED, tree vdef, void *data)
|
||||||
|
|
||||||
if (stmt_may_be_vtbl_ptr_store (stmt))
|
if (stmt_may_be_vtbl_ptr_store (stmt))
|
||||||
{
|
{
|
||||||
|
tree type;
|
||||||
|
type = extr_type_from_vtbl_ptr_store (stmt, tci);
|
||||||
|
if (tci->type_maybe_changed
|
||||||
|
&& type != tci->known_current_type)
|
||||||
|
tci->multiple_types_encountered = true;
|
||||||
|
tci->known_current_type = type;
|
||||||
tci->type_maybe_changed = true;
|
tci->type_maybe_changed = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -359,6 +421,60 @@ check_stmt_for_type_change (ao_ref *ao ATTRIBUTE_UNUSED, tree vdef, void *data)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Like detect_type_change but with extra argument COMP_TYPE which will become
|
||||||
|
the component type part of new JFUNC of dynamic type change is detected and
|
||||||
|
the new base type is identified. */
|
||||||
|
|
||||||
|
static bool
|
||||||
|
detect_type_change_1 (tree arg, tree base, tree comp_type, gimple call,
|
||||||
|
struct ipa_jump_func *jfunc, HOST_WIDE_INT offset)
|
||||||
|
{
|
||||||
|
struct type_change_info tci;
|
||||||
|
ao_ref ao;
|
||||||
|
|
||||||
|
gcc_checking_assert (DECL_P (arg)
|
||||||
|
|| TREE_CODE (arg) == MEM_REF
|
||||||
|
|| handled_component_p (arg));
|
||||||
|
/* Const calls cannot call virtual methods through VMT and so type changes do
|
||||||
|
not matter. */
|
||||||
|
if (!flag_devirtualize || !gimple_vuse (call))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
ao.ref = arg;
|
||||||
|
ao.base = base;
|
||||||
|
ao.offset = offset;
|
||||||
|
ao.size = POINTER_SIZE;
|
||||||
|
ao.max_size = ao.size;
|
||||||
|
ao.ref_alias_set = -1;
|
||||||
|
ao.base_alias_set = -1;
|
||||||
|
|
||||||
|
tci.offset = offset;
|
||||||
|
tci.object = get_base_address (arg);
|
||||||
|
tci.known_current_type = NULL_TREE;
|
||||||
|
tci.type_maybe_changed = false;
|
||||||
|
tci.multiple_types_encountered = false;
|
||||||
|
|
||||||
|
walk_aliased_vdefs (&ao, gimple_vuse (call), check_stmt_for_type_change,
|
||||||
|
&tci, NULL);
|
||||||
|
if (!tci.type_maybe_changed)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!tci.known_current_type
|
||||||
|
|| tci.multiple_types_encountered
|
||||||
|
|| offset != 0)
|
||||||
|
jfunc->type = IPA_JF_UNKNOWN;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
jfunc->type = IPA_JF_KNOWN_TYPE;
|
||||||
|
jfunc->value.known_type.base_type = tci.known_current_type;
|
||||||
|
jfunc->value.known_type.component_type = comp_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/* Detect whether the dynamic type of ARG has changed (before callsite CALL) by
|
/* Detect whether the dynamic type of ARG has changed (before callsite CALL) by
|
||||||
looking for assignments to its virtual table pointer. If it is, return true
|
looking for assignments to its virtual table pointer. If it is, return true
|
||||||
and fill in the jump function JFUNC with relevant type information or set it
|
and fill in the jump function JFUNC with relevant type information or set it
|
||||||
|
@ -370,34 +486,7 @@ static bool
|
||||||
detect_type_change (tree arg, tree base, gimple call,
|
detect_type_change (tree arg, tree base, gimple call,
|
||||||
struct ipa_jump_func *jfunc, HOST_WIDE_INT offset)
|
struct ipa_jump_func *jfunc, HOST_WIDE_INT offset)
|
||||||
{
|
{
|
||||||
struct type_change_info tci;
|
return detect_type_change_1 (arg, base, TREE_TYPE (arg), call, jfunc, offset);
|
||||||
ao_ref ao;
|
|
||||||
|
|
||||||
gcc_checking_assert (DECL_P (arg)
|
|
||||||
|| TREE_CODE (arg) == MEM_REF
|
|
||||||
|| handled_component_p (arg));
|
|
||||||
/* Const calls cannot call virtual methods through VMT and so type changes do
|
|
||||||
not matter. */
|
|
||||||
if (!flag_devirtualize || !gimple_vuse (call))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
tci.type_maybe_changed = false;
|
|
||||||
|
|
||||||
ao.ref = arg;
|
|
||||||
ao.base = base;
|
|
||||||
ao.offset = offset;
|
|
||||||
ao.size = POINTER_SIZE;
|
|
||||||
ao.max_size = ao.size;
|
|
||||||
ao.ref_alias_set = -1;
|
|
||||||
ao.base_alias_set = -1;
|
|
||||||
|
|
||||||
walk_aliased_vdefs (&ao, gimple_vuse (call), check_stmt_for_type_change,
|
|
||||||
&tci, NULL);
|
|
||||||
if (!tci.type_maybe_changed)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
jfunc->type = IPA_JF_UNKNOWN;
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Like detect_type_change but ARG is supposed to be a non-dereferenced pointer
|
/* Like detect_type_change but ARG is supposed to be a non-dereferenced pointer
|
||||||
|
@ -407,16 +496,19 @@ detect_type_change (tree arg, tree base, gimple call,
|
||||||
static bool
|
static bool
|
||||||
detect_type_change_ssa (tree arg, gimple call, struct ipa_jump_func *jfunc)
|
detect_type_change_ssa (tree arg, gimple call, struct ipa_jump_func *jfunc)
|
||||||
{
|
{
|
||||||
|
tree comp_type;
|
||||||
|
|
||||||
gcc_checking_assert (TREE_CODE (arg) == SSA_NAME);
|
gcc_checking_assert (TREE_CODE (arg) == SSA_NAME);
|
||||||
if (!flag_devirtualize
|
if (!flag_devirtualize
|
||||||
|| !POINTER_TYPE_P (TREE_TYPE (arg))
|
|| !POINTER_TYPE_P (TREE_TYPE (arg))
|
||||||
|| TREE_CODE (TREE_TYPE (TREE_TYPE (arg))) != RECORD_TYPE)
|
|| TREE_CODE (TREE_TYPE (TREE_TYPE (arg))) != RECORD_TYPE)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
comp_type = TREE_TYPE (TREE_TYPE (arg));
|
||||||
arg = build2 (MEM_REF, ptr_type_node, arg,
|
arg = build2 (MEM_REF, ptr_type_node, arg,
|
||||||
build_int_cst (ptr_type_node, 0));
|
build_int_cst (ptr_type_node, 0));
|
||||||
|
|
||||||
return detect_type_change (arg, arg, call, jfunc, 0);
|
return detect_type_change_1 (arg, arg, comp_type, call, jfunc, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Callback of walk_aliased_vdefs. Flags that it has been invoked to the
|
/* Callback of walk_aliased_vdefs. Flags that it has been invoked to the
|
||||||
|
|
|
@ -1,3 +1,10 @@
|
||||||
|
2011-11-03 Martin Jambor <mjambor@suse.cz>
|
||||||
|
|
||||||
|
* g++.dg/ipa/devirt-c-1.C: Add dump scans.
|
||||||
|
* g++.dg/ipa/devirt-c-2.C: Likewise.
|
||||||
|
* g++.dg/ipa/devirt-c-7.C: New test.
|
||||||
|
* g++.dg/ipa/devirt-c-8.C: Likewise.
|
||||||
|
|
||||||
2011-11-03 Ira Rosen <ira.rosen@linaro.org>
|
2011-11-03 Ira Rosen <ira.rosen@linaro.org>
|
||||||
|
|
||||||
PR tree-optimization/50912
|
PR tree-optimization/50912
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/* Verify that ipa-cp correctly detects the dynamic type of an object
|
/* Verify that ipa-cp correctly detects the dynamic type of an object
|
||||||
under construction when doing devirtualization. */
|
under construction when doing devirtualization. */
|
||||||
/* { dg-do run } */
|
/* { dg-do run } */
|
||||||
/* { dg-options "-O3 -fno-early-inlining -fno-inline" } */
|
/* { dg-options "-O3 -fno-early-inlining -fno-inline -fdump-ipa-cp -fdump-tree-optimized" } */
|
||||||
|
|
||||||
extern "C" void abort (void);
|
extern "C" void abort (void);
|
||||||
|
|
||||||
|
@ -69,3 +69,8 @@ int main (int argc, char *argv[])
|
||||||
bah ();
|
bah ();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* { dg-final { scan-ipa-dump "Discovered a virtual call to a known target.*A::foo" "cp" } } */
|
||||||
|
/* { dg-final { scan-tree-dump-times "OBJ_TYPE_REF" 0 "optimized"} } */
|
||||||
|
/* { dg-final { cleanup-ipa-dump "cp" } } */
|
||||||
|
/* { dg-final { cleanup-tree-dump "optimized" } } */
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/* Verify that ipa-cp correctly detects the dynamic type of an object
|
/* Verify that ipa-cp correctly detects the dynamic type of an object
|
||||||
under construction when doing devirtualization. */
|
under construction when doing devirtualization. */
|
||||||
/* { dg-do run } */
|
/* { dg-do run } */
|
||||||
/* { dg-options "-O3 -fno-early-inlining -fno-inline" } */
|
/* { dg-options "-O3 -fno-early-inlining -fno-inline -fdump-ipa-cp -fdump-tree-optimized" } */
|
||||||
|
|
||||||
extern "C" void abort (void);
|
extern "C" void abort (void);
|
||||||
|
|
||||||
|
@ -77,3 +77,8 @@ int main (int argc, char *argv[])
|
||||||
bah ();
|
bah ();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* { dg-final { scan-ipa-dump "Discovered a virtual call to a known target.*A::foo" "cp" } } */
|
||||||
|
/* { dg-final { scan-tree-dump-times "OBJ_TYPE_REF" 0 "optimized"} } */
|
||||||
|
/* { dg-final { cleanup-ipa-dump "cp" } } */
|
||||||
|
/* { dg-final { cleanup-tree-dump "optimized" } } */
|
||||||
|
|
87
gcc/testsuite/g++.dg/ipa/devirt-c-7.C
Normal file
87
gcc/testsuite/g++.dg/ipa/devirt-c-7.C
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
/* Verify that ipa-cp will not get confused by placement new constructing an
|
||||||
|
object within another one when looking for dynamic type change . */
|
||||||
|
/* { dg-do run } */
|
||||||
|
/* { dg-options "-O3 -Wno-attributes" } */
|
||||||
|
|
||||||
|
extern "C" void abort (void);
|
||||||
|
namespace std {
|
||||||
|
typedef __SIZE_TYPE__ size_t;
|
||||||
|
}
|
||||||
|
inline void* __attribute__ ((always_inline))
|
||||||
|
operator new(std::size_t, void* __p) throw()
|
||||||
|
{
|
||||||
|
return __p;
|
||||||
|
}
|
||||||
|
|
||||||
|
class A
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
char data[256];
|
||||||
|
A();
|
||||||
|
virtual int foo (int i);
|
||||||
|
};
|
||||||
|
|
||||||
|
class B : public A
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual int foo (int i);
|
||||||
|
};
|
||||||
|
|
||||||
|
class C
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
C();
|
||||||
|
virtual double foo (double i);
|
||||||
|
};
|
||||||
|
|
||||||
|
int A::foo (int i)
|
||||||
|
{
|
||||||
|
return i + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int B::foo (int i)
|
||||||
|
{
|
||||||
|
return i + 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
double C::foo (double i)
|
||||||
|
{
|
||||||
|
return i + 3.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __attribute__ ((noinline)) middleman (class A *obj, int i)
|
||||||
|
{
|
||||||
|
return obj->foo (i);
|
||||||
|
}
|
||||||
|
|
||||||
|
int __attribute__ ((noinline,noclone)) get_input(void)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__ ((always_inline)) C::C ()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
A::A ()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static __attribute__ ((noinline)) void bah ()
|
||||||
|
{
|
||||||
|
class B b;
|
||||||
|
|
||||||
|
C *c = new ((void *) &b.data) C;
|
||||||
|
|
||||||
|
if (middleman (&b, get_input ()) != 3)
|
||||||
|
abort ();
|
||||||
|
}
|
||||||
|
|
||||||
|
int main (int argc, char *argv[])
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < 10; i++)
|
||||||
|
bah ();
|
||||||
|
return 0;
|
||||||
|
}
|
82
gcc/testsuite/g++.dg/ipa/devirt-c-8.C
Normal file
82
gcc/testsuite/g++.dg/ipa/devirt-c-8.C
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
/* Verify that ipa-cp correctly detects the dynamic type of an object
|
||||||
|
under construction when doing devirtualization. */
|
||||||
|
/* { dg-do run } */
|
||||||
|
/* { dg-options "-O3 -fno-early-inlining -fno-inline -fdump-ipa-cp -fdump-tree-optimized" } */
|
||||||
|
|
||||||
|
extern "C" void abort (void);
|
||||||
|
|
||||||
|
class A
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
int data;
|
||||||
|
A();
|
||||||
|
virtual int foo (int i);
|
||||||
|
};
|
||||||
|
|
||||||
|
class B : public A
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
B();
|
||||||
|
virtual int foo (int i);
|
||||||
|
};
|
||||||
|
|
||||||
|
class C : public A
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual int foo (int i);
|
||||||
|
};
|
||||||
|
|
||||||
|
int A::foo (int i)
|
||||||
|
{
|
||||||
|
return i + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int B::foo (int i)
|
||||||
|
{
|
||||||
|
return i + 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
int C::foo (int i)
|
||||||
|
{
|
||||||
|
return i + 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __attribute__ ((noinline))
|
||||||
|
middleman (class A *obj, int i)
|
||||||
|
{
|
||||||
|
return obj->foo (i);
|
||||||
|
}
|
||||||
|
|
||||||
|
int __attribute__ ((noinline,noclone)) get_input(void)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline __attribute__ ((always_inline)) A::A ()
|
||||||
|
{
|
||||||
|
if (middleman (this, get_input ()) != 2)
|
||||||
|
abort ();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline __attribute__ ((always_inline)) B::B ()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static void bah ()
|
||||||
|
{
|
||||||
|
class B b;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main (int argc, char *argv[])
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < 10; i++)
|
||||||
|
bah ();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* { dg-final { scan-ipa-dump "Discovered a virtual call to a known target.*A::foo" "cp" } } */
|
||||||
|
/* { dg-final { scan-tree-dump-times "OBJ_TYPE_REF" 0 "optimized"} } */
|
||||||
|
/* { dg-final { cleanup-ipa-dump "cp" } } */
|
||||||
|
/* { dg-final { cleanup-tree-dump "optimized" } } */
|
|
@ -2686,7 +2686,9 @@ struct function;
|
||||||
nodes, this points to either the FUNCTION_DECL for the containing
|
nodes, this points to either the FUNCTION_DECL for the containing
|
||||||
function, the RECORD_TYPE or UNION_TYPE for the containing type, or
|
function, the RECORD_TYPE or UNION_TYPE for the containing type, or
|
||||||
NULL_TREE or a TRANSLATION_UNIT_DECL if the given decl has "file
|
NULL_TREE or a TRANSLATION_UNIT_DECL if the given decl has "file
|
||||||
scope". */
|
scope". In particular, for VAR_DECLs which are virtual table pointers
|
||||||
|
(they have DECL_VIRTUAL set), we use DECL_CONTEXT to determine the type
|
||||||
|
they belong to. */
|
||||||
#define DECL_CONTEXT(NODE) (DECL_MINIMAL_CHECK (NODE)->decl_minimal.context)
|
#define DECL_CONTEXT(NODE) (DECL_MINIMAL_CHECK (NODE)->decl_minimal.context)
|
||||||
#define DECL_FIELD_CONTEXT(NODE) \
|
#define DECL_FIELD_CONTEXT(NODE) \
|
||||||
(FIELD_DECL_CHECK (NODE)->decl_minimal.context)
|
(FIELD_DECL_CHECK (NODE)->decl_minimal.context)
|
||||||
|
|
Loading…
Add table
Reference in a new issue