Changeset 2a301ff for src/InitTweak/GenInit.cc
- Timestamp:
- Aug 31, 2023, 11:31:15 PM (2 years ago)
- Branches:
- master
- Children:
- 950c58e
- Parents:
- 92355883 (diff), 686912c (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)
links above to see all the changes relative to each parent. - File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
src/InitTweak/GenInit.cc
r92355883 r2a301ff 300 300 301 301 # warning Remove the _New suffix after the conversion is complete. 302 303 // Outer pass finds declarations, for their type could wrap a type that needs hoisting 302 304 struct HoistArrayDimension_NoResolve_New final : 303 305 public ast::WithDeclsToAdd<>, public ast::WithShortCircuiting, 304 306 public ast::WithGuards, public ast::WithConstTranslationUnit, 305 public ast::WithVisitorRef<HoistArrayDimension_NoResolve_New> { 306 void previsit( const ast::ObjectDecl * decl ); 307 const ast::DeclWithType * postvisit( const ast::ObjectDecl * decl ); 308 // Do not look for objects inside there declarations (and type). 309 void previsit( const ast::AggregateDecl * ) { visit_children = false; } 310 void previsit( const ast::NamedTypeDecl * ) { visit_children = false; } 311 void previsit( const ast::FunctionType * ) { visit_children = false; } 312 313 const ast::Type * hoist( const ast::Type * type ); 307 public ast::WithVisitorRef<HoistArrayDimension_NoResolve_New>, 308 public ast::WithSymbolTableX<ast::SymbolTable::ErrorDetection::IgnoreErrors> { 309 310 // Inner pass looks within a type, for a part that depends on an expression 311 struct HoistDimsFromTypes final : 312 public ast::WithShortCircuiting, public ast::WithGuards { 313 314 HoistArrayDimension_NoResolve_New * outer; 315 HoistDimsFromTypes( HoistArrayDimension_NoResolve_New * outer ) : outer(outer) {} 316 317 // Only intended for visiting through types. 318 // Tolerate, and short-circuit at, the dimension expression of an array type. 319 // (We'll operate on the dimension expression of an array type directly 320 // from the parent type, not by visiting through it) 321 // Look inside type exprs. 322 void previsit( const ast::Node * ) { 323 assert( false && "unsupported node type" ); 324 }; 325 const ast::Expr * allowedExpr = nullptr; 326 void previsit( const ast::Type * ) { 327 GuardValue( allowedExpr ) = nullptr; 328 } 329 void previsit( const ast::ArrayType * t ) { 330 GuardValue( allowedExpr ) = t->dimension.get(); 331 } 332 void previsit( const ast::PointerType * t ) { 333 GuardValue( allowedExpr ) = t->dimension.get(); 334 } 335 void previsit( const ast::TypeofType * t ) { 336 GuardValue( allowedExpr ) = t->expr.get(); 337 } 338 void previsit( const ast::Expr * e ) { 339 assert( e == allowedExpr && 340 "only expecting to visit exprs that are dimension exprs or typeof(-) inner exprs" ); 341 342 // Skip the tolerated expressions 343 visit_children = false; 344 } 345 void previsit( const ast::TypeExpr * ) {} 346 347 const ast::Type * postvisit( 348 const ast::ArrayType * arrayType ) { 349 static UniqueName dimensionName( "_array_dim" ); 350 351 if ( nullptr == arrayType->dimension ) { // if no dimension is given, don't presume to invent one 352 return arrayType; 353 } 354 355 // find size_t; use it as the type for a dim expr 356 ast::ptr<ast::Type> dimType = outer->transUnit().global.sizeType; 357 assert( dimType ); 358 add_qualifiers( dimType, ast::CV::Qualifiers( ast::CV::Const ) ); 359 360 // Special-case handling: leave the user's dimension expression alone 361 // - requires the user to have followed a careful convention 362 // - may apply to extremely simple applications, but only as windfall 363 // - users of advanced applications will be following the convention on purpose 364 // - CFA maintainers must protect the criteria against leaving too much alone 365 366 // Actual leave-alone cases following are conservative approximations of "cannot vary" 367 368 // Leave alone: literals and enum constants 369 if ( dynamic_cast< const ast::ConstantExpr * >( arrayType->dimension.get() ) ) { 370 return arrayType; 371 } 372 373 // Leave alone: direct use of an object declared to be const 374 const ast::NameExpr * dimn = dynamic_cast< const ast::NameExpr * >( arrayType->dimension.get() ); 375 if ( dimn ) { 376 std::vector<ast::SymbolTable::IdData> dimnDefs = outer->symtab.lookupId( dimn->name ); 377 if ( dimnDefs.size() == 1 ) { 378 const ast::DeclWithType * dimnDef = dimnDefs[0].id.get(); 379 assert( dimnDef && "symbol table binds a name to nothing" ); 380 const ast::ObjectDecl * dimOb = dynamic_cast< const ast::ObjectDecl * >( dimnDef ); 381 if( dimOb ) { 382 const ast::Type * dimTy = dimOb->type.get(); 383 assert( dimTy && "object declaration bearing no type" ); 384 // must not hoist some: size_t 385 // must hoist all: pointers and references 386 // the analysis is conservative; BasicType is a simple approximation 387 if ( dynamic_cast< const ast::BasicType * >( dimTy ) || 388 dynamic_cast< const ast::SueInstType<ast::EnumDecl> * >( dimTy ) ) { 389 if ( dimTy->is_const() ) { 390 // The dimension is certainly re-evaluable, giving the same answer each time. 391 // Our user might be hoping to write the array type in multiple places, having them unify. 392 // Leave the type alone. 393 394 // We believe the new criterion leaves less alone than the old criterion. 395 // Thus, the old criterion should have left the current case alone. 396 // Catch cases that weren't thought through. 397 assert( !Tuples::maybeImpure( arrayType->dimension ) ); 398 399 return arrayType; 400 } 401 }; 402 } 403 } 404 } 405 406 // Leave alone: any sizeof expression (answer cannot vary during current lexical scope) 407 const ast::SizeofExpr * sz = dynamic_cast< const ast::SizeofExpr * >( arrayType->dimension.get() ); 408 if ( sz ) { 409 return arrayType; 410 } 411 412 // General-case handling: change the array-type's dim expr (hoist the user-given content out of the type) 413 // - always safe 414 // - user-unnoticeable in common applications (benign noise in -CFA output) 415 // - may annoy a responsible user of advanced applications (but they can work around) 416 // - protects against misusing advanced features 417 // 418 // The hoist, by example, is: 419 // FROM USER: float a[ rand() ]; 420 // TO GCC: const size_t __len_of_a = rand(); float a[ __len_of_a ]; 421 422 ast::ObjectDecl * arrayDimension = new ast::ObjectDecl( 423 arrayType->dimension->location, 424 dimensionName.newName(), 425 dimType, 426 new ast::SingleInit( 427 arrayType->dimension->location, 428 arrayType->dimension 429 ) 430 ); 431 432 ast::ArrayType * mutType = ast::mutate( arrayType ); 433 mutType->dimension = new ast::VariableExpr( 434 arrayDimension->location, arrayDimension ); 435 outer->declsToAddBefore.push_back( arrayDimension ); 436 437 return mutType; 438 } // postvisit( const ast::ArrayType * ) 439 }; // struct HoistDimsFromTypes 314 440 315 441 ast::Storage::Classes storageClasses; 442 void previsit( 443 const ast::ObjectDecl * decl ) { 444 GuardValue( storageClasses ) = decl->storage; 445 } 446 447 const ast::DeclWithType * postvisit( 448 const ast::ObjectDecl * objectDecl ) { 449 450 if ( !isInFunction() || storageClasses.is_static ) { 451 return objectDecl; 452 } 453 454 const ast::Type * mid = objectDecl->type; 455 456 ast::Pass<HoistDimsFromTypes> hoist{this}; 457 const ast::Type * result = mid->accept( hoist ); 458 459 return mutate_field( objectDecl, &ast::ObjectDecl::type, result ); 460 } 316 461 }; 317 462 318 void HoistArrayDimension_NoResolve_New::previsit( 319 const ast::ObjectDecl * decl ) { 320 GuardValue( storageClasses ) = decl->storage; 321 } 322 323 const ast::DeclWithType * HoistArrayDimension_NoResolve_New::postvisit( 324 const ast::ObjectDecl * objectDecl ) { 325 return mutate_field( objectDecl, &ast::ObjectDecl::type, 326 hoist( objectDecl->type ) ); 327 } 328 329 const ast::Type * HoistArrayDimension_NoResolve_New::hoist( 330 const ast::Type * type ) { 331 static UniqueName dimensionName( "_array_dim" ); 332 333 if ( !isInFunction() || storageClasses.is_static ) { 334 return type; 335 } 336 337 if ( auto arrayType = dynamic_cast< const ast::ArrayType * >( type ) ) { 338 if ( nullptr == arrayType->dimension ) { 339 return type; 340 } 341 342 if ( !Tuples::maybeImpure( arrayType->dimension ) ) { 343 return type; 344 } 345 346 ast::ptr<ast::Type> dimType = transUnit().global.sizeType; 347 assert( dimType ); 348 add_qualifiers( dimType, ast::CV::Qualifiers( ast::CV::Const ) ); 349 350 ast::ObjectDecl * arrayDimension = new ast::ObjectDecl( 351 arrayType->dimension->location, 352 dimensionName.newName(), 353 dimType, 354 new ast::SingleInit( 355 arrayType->dimension->location, 356 arrayType->dimension 357 ) 358 ); 359 360 ast::ArrayType * mutType = ast::mutate( arrayType ); 361 mutType->dimension = new ast::VariableExpr( 362 arrayDimension->location, arrayDimension ); 363 declsToAddBefore.push_back( arrayDimension ); 364 365 mutType->base = hoist( mutType->base ); 366 return mutType; 367 } 368 return type; 369 } 463 464 370 465 371 466 struct ReturnFixer_New final :
Note:
See TracChangeset
for help on using the changeset viewer.