1 include("gcc_util.js");
2 include("unstable/lazy_types.js");
4 function process_type(c
)
6 if ((c
.kind
== 'class' || c
.kind
== 'struct') &&
12 * A BlameChain records a chain of one or more location/message pairs. It
13 * can be used to issue a complex error message such as:
14 * location: error: Allocated class Foo on the heap
15 * locationofFoo: class Foo inherits from class Bar
16 * locationofBar: in class Bar
17 * locationofBarMem: Member Bar::mFoo
18 * locationofBaz: class Baz is annotated NS_STACK
20 function BlameChain(loc
, message
, prev
)
23 this.message
= message
;
26 BlameChain
.prototype.toString = function()
29 if (loc
=== undefined)
30 loc
= "<unknown location>";
32 let str
= '%s: %s'.format(loc
.toString(), this.message
);
34 str
+= "\n%s".format(this.prev
);
42 if (hasAttribute(c
, 'NS_stack'))
43 return new BlameChain(c
.loc
, '%s %s is annotated NS_STACK_CLASS'.format(c
.kind
, c
.name
));
45 for each (let base
in c
.bases
) {
46 let r
= isStack(base
.type
);
48 return new BlameChain(c
.loc
, '%s %s is a base of %s %s'.format(base
.type
.kind
, base
.type
.name
, c
.kind
, c
.name
), r
);
51 for each (let member
in c
.members
) {
52 if (member
.isFunction
)
55 if (hasAttribute(member
, 'NS_okonheap'))
58 let type
= member
.type
;
60 if (type
=== undefined)
69 if (hasAttribute(type
, 'NS_stack'))
78 if (type
=== undefined) {
79 warning("incomplete type for member " + member
+ ".", member
.loc
);
83 if (type
.isPointer
|| type
.isReference
)
86 if (!type
.kind
|| (type
.kind
!= 'class' && type
.kind
!= 'struct'))
89 let r
= isStack(type
);
91 return new BlameChain(c
.loc
, 'In class %s'.format(c
.name
),
92 new BlameChain(member
.loc
, 'Member %s'.format(member
.name
), r
));
98 throw Error("Can't get stack property for incomplete type.");
100 if (!c
.hasOwnProperty('isStack'))
101 c
.isStack
= calculate();
106 function isVoidPtr(t
)
108 return t
.isPointer
&& t
.type
.name
== 'void';
111 function xrange(start
, end
, skip
)
114 (skip
> 0) ? (start
< end
) : (start
> end
);
119 function process_cp_pre_genericize(fndecl
)
121 function findconstructors(t
, stack
)
123 function getLocation() {
124 let loc
= location_of(t
);
125 if (loc
!== undefined)
128 for (let i
= stack
.length
- 1; i
>= 0; --i
) {
129 loc
= location_of(stack
[i
]);
130 if (loc
!== undefined)
133 return location_of(DECL_SAVED_TREE(fndecl
));
137 t
.tree_check(CALL_EXPR
);
139 callable_arg_function_decl(CALL_EXPR_FN(t
));
143 let nameid
= DECL_NAME(fncall
);
144 if (IDENTIFIER_OPNAME_P(nameid
)) {
145 let name
= IDENTIFIER_POINTER(nameid
);
147 if (name
== "operator new" || name
== "operator new []") {
148 let fncallobj
= dehydra_convert(TREE_TYPE(fncall
));
149 if (fncallobj
.parameters
.length
== 2 &&
150 isVoidPtr(fncallobj
.parameters
[1]))
154 for (i
in xrange(stack
.length
- 1, -1, -1)) {
155 if (TREE_CODE(stack
[i
]) != NOP_EXPR
)
158 let assign
= stack
[i
];
159 switch (TREE_CODE(assign
)) {
166 assign
= assign
.operands()[1];
170 assign
= stack
[i
+ 1];
174 error("Unrecognized assignment from operator new: " + TREE_CODE(assign
), getLocation());
178 let destType
= dehydra_convert(TREE_TYPE(assign
));
179 if (!destType
.isPointer
&& !destType
.isReference
) {
180 error("operator new not assigned to pointer/ref?", getLocation());
183 destType
= destType
.type
;
185 let r
= isStack(destType
);
187 error("constructed object of type '%s' not on the stack: %s".format(destType
.name
, r
), getLocation());
191 catch (e
if e
.TreeCheckError
) { }
194 if (hasAttribute(dehydra_convert(fndecl
), 'NS_suppress_stackcheck'))
197 walk_tree(DECL_SAVED_TREE(fndecl
), findconstructors
);