2008-06-30 09:44:06 -07:00
include ( "gcc_util.js" ) ;
include ( "unstable/lazy_types.js" ) ;
function process _type ( c )
{
if ( ( c . kind == 'class' || c . kind == 'struct' ) &&
! c . isIncomplete )
isStack ( c ) ;
}
2008-09-03 10:00:13 -07:00
/ * *
* A BlameChain records a chain of one or more location / message pairs . It
* can be used to issue a complex error message such as :
* location : error : Allocated class Foo on the heap
* locationofFoo : class Foo inherits from class Bar
* locationofBar : in class Bar
* locationofBarMem : Member Bar : : mFoo
* locationofBaz : class Baz is annotated NS _STACK
* /
function BlameChain ( loc , message , prev )
{
this . loc = loc ;
this . message = message ;
this . prev = prev ;
}
BlameChain . prototype . toString = function ( )
{
let loc = this . loc ;
if ( loc === undefined )
loc = "<unknown location>" ;
let str = '%s: %s' . format ( loc . toString ( ) , this . message ) ;
if ( this . prev )
str += "\n%s" . format ( this . prev ) ;
return str ;
} ;
2008-06-30 09:44:06 -07:00
function isStack ( c )
2008-06-06 12:31:11 -07:00
{
2008-06-30 09:44:06 -07:00
function calculate ( )
2008-06-06 12:31:11 -07:00
{
2008-06-30 09:44:06 -07:00
if ( hasAttribute ( c , 'NS_stack' ) )
2008-09-03 10:00:13 -07:00
return new BlameChain ( c . loc , '%s %s is annotated NS_STACK_CLASS' . format ( c . kind , c . name ) ) ;
2008-06-30 09:44:06 -07:00
2008-09-03 10:00:13 -07:00
for each ( let base in c . bases ) {
let r = isStack ( base . type ) ;
if ( r != null )
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 ) ;
}
2008-06-30 09:44:06 -07:00
for each ( let member in c . members ) {
if ( member . isFunction )
2008-06-30 12:35:11 -07:00
continue ;
2008-06-30 09:44:06 -07:00
2008-08-27 07:58:50 -07:00
if ( hasAttribute ( member , 'NS_okonheap' ) )
continue ;
2008-06-30 09:44:06 -07:00
let type = member . type ;
while ( true ) {
2008-06-30 12:35:11 -07:00
if ( type === undefined )
break ;
if ( type . isArray ) {
type = type . type ;
continue ;
}
if ( type . typedef ) {
if ( hasAttribute ( type , 'NS_stack' ) )
return true ;
type = type . typedef ;
continue ;
}
break ;
2008-06-30 09:44:06 -07:00
}
if ( type === undefined ) {
2008-06-30 12:35:11 -07:00
warning ( "incomplete type for member " + member + "." , member . loc ) ;
continue ;
2008-06-30 09:44:06 -07:00
}
2008-06-06 12:31:11 -07:00
2008-06-30 09:44:06 -07:00
if ( type . isPointer || type . isReference )
2008-06-30 12:35:11 -07:00
continue ;
2008-06-30 09:44:06 -07:00
if ( ! type . kind || ( type . kind != 'class' && type . kind != 'struct' ) )
2008-06-30 12:35:11 -07:00
continue ;
2008-06-30 09:44:06 -07:00
2008-09-03 10:00:13 -07:00
let r = isStack ( type ) ;
if ( r != null )
return new BlameChain ( c . loc , 'In class %s' . format ( c . name ) ,
new BlameChain ( member . loc , 'Member %s' . format ( member . name ) , r ) ) ;
2008-06-30 09:44:06 -07:00
}
2008-09-03 10:00:13 -07:00
return null ;
2008-06-06 12:31:11 -07:00
}
2008-06-30 09:44:06 -07:00
if ( c . isIncomplete )
throw Error ( "Can't get stack property for incomplete type." ) ;
if ( ! c . hasOwnProperty ( 'isStack' ) )
c . isStack = calculate ( ) ;
return c . isStack ;
}
function isVoidPtr ( t )
{
return t . isPointer && t . type . name == 'void' ;
}
2008-09-03 10:00:13 -07:00
function xrange ( start , end , skip )
2008-06-30 09:44:06 -07:00
{
2008-09-03 10:00:13 -07:00
for ( ;
( skip > 0 ) ? ( start < end ) : ( start > end ) ;
start += skip )
yield start ;
2008-06-30 09:44:06 -07:00
}
2008-09-03 10:00:13 -07:00
function process _cp _pre _genericize ( fndecl )
2008-06-30 09:44:06 -07:00
{
function findconstructors ( t , stack )
{
2008-09-03 10:00:13 -07:00
function getLocation ( ) {
let loc = location _of ( t ) ;
if ( loc !== undefined )
return loc ;
2008-06-30 09:44:06 -07:00
for ( let i = stack . length - 1 ; i >= 0 ; -- i ) {
2008-09-03 10:00:13 -07:00
loc = location _of ( stack [ i ] ) ;
2008-06-30 09:44:06 -07:00
if ( loc !== undefined )
return loc ;
}
return location _of ( DECL _SAVED _TREE ( fndecl ) ) ;
}
2008-09-03 10:00:13 -07:00
try {
t . tree _check ( CALL _EXPR ) ;
let fncall =
callable _arg _function _decl ( CALL _EXPR _FN ( t ) ) ;
if ( fncall == null )
2008-06-30 09:44:06 -07:00
return ;
2008-09-03 10:00:13 -07:00
let nameid = DECL _NAME ( fncall ) ;
if ( IDENTIFIER _OPNAME _P ( nameid ) ) {
let name = IDENTIFIER _POINTER ( nameid ) ;
if ( name == "operator new" || name == "operator new []" ) {
let fncallobj = dehydra _convert ( TREE _TYPE ( fncall ) ) ;
if ( fncallobj . parameters . length == 2 &&
isVoidPtr ( fncallobj . parameters [ 1 ] ) )
return ;
let i ;
for ( i in xrange ( stack . length - 1 , - 1 , - 1 ) ) {
if ( TREE _CODE ( stack [ i ] ) != NOP _EXPR )
break ;
}
let assign = stack [ i ] ;
switch ( TREE _CODE ( assign ) ) {
case VAR _DECL :
break ;
case INIT _EXPR :
case MODIFY _EXPR :
case TARGET _EXPR :
assign = assign . operands ( ) [ 1 ] ;
break ;
case CALL _EXPR :
2008-12-03 08:49:54 -08:00
case AGGR _INIT _EXPR :
2008-09-03 10:00:13 -07:00
assign = stack [ i + 1 ] ;
break ;
default :
2008-12-03 08:49:54 -08:00
error ( "Unrecognized assignment from operator new: %s. Tree code stack: %s" . format ( TREE _CODE ( assign ) , [ TREE _CODE ( s ) for each ( s in stack ) ] . join ( "," ) ) , getLocation ( ) ) ;
2008-09-03 10:00:13 -07:00
return ;
}
let destType = dehydra _convert ( TREE _TYPE ( assign ) ) ;
if ( ! destType . isPointer && ! destType . isReference ) {
error ( "operator new not assigned to pointer/ref?" , getLocation ( ) ) ;
return ;
}
destType = destType . type ;
let r = isStack ( destType ) ;
if ( r )
2008-12-01 10:59:58 -08:00
warning ( "constructed object of type '%s' not on the stack: %s" . format ( destType . name , r ) , getLocation ( ) ) ;
2008-09-03 10:00:13 -07:00
}
2008-06-30 09:44:06 -07:00
}
}
2008-09-03 10:00:13 -07:00
catch ( e if e . TreeCheckError ) { }
2008-06-06 12:31:11 -07:00
}
2008-09-03 10:00:12 -07:00
if ( hasAttribute ( dehydra _convert ( fndecl ) , 'NS_suppress_stackcheck' ) )
return ;
2008-06-30 09:44:06 -07:00
2008-09-03 10:00:13 -07:00
walk _tree ( DECL _SAVED _TREE ( fndecl ) , findconstructors ) ;
2008-06-06 12:31:11 -07:00
}