- Timestamp:
- Apr 26, 2026, 5:46:08 PM (6 weeks ago)
- Branches:
- stuck-waitfor-destruct
- Parents:
- 88bb0b4
- git-author:
- Matthew Au-Yeung <mw2auyeu@…> (04/26/26 17:44:48)
- git-committer:
- Matthew Au-Yeung <mw2auyeu@…> (04/26/26 17:46:08)
- Location:
- src
- Files:
-
- 2 edited
-
CodeGen/LinkOnce.cpp (modified) (5 diffs)
-
Validate/Autogen.cpp (modified) (4 diffs)
Legend:
- Unmodified
- Added
- Removed
-
src/CodeGen/LinkOnce.cpp
r88bb0b4 rd8a3073 22 22 #include "AST/Expr.hpp" 23 23 #include "AST/Pass.hpp" 24 #include "CompilationState.hpp" 25 #include "InitTweak/InitTweak.hpp" 24 26 25 27 namespace CodeGen { … … 33 35 bool is_section_attribute( ast::Attribute const * attr ) { 34 36 return "section" == attr->name; 37 } 38 39 bool is_visibility_attribute( ast::Attribute const * attr ) { 40 return "visibility" == attr->name; 35 41 } 36 42 … … 60 66 ast::Attribute * attribute = found->get_and_mutate(); 61 67 assert( attribute->params.empty() ); 62 assert( !decl->mangleName.empty() );63 68 64 69 attribute->name = "section"; … … 69 74 ); 70 75 71 // Unconditionnaly add "visibility(default)" to anything with72 // .gnu.linkonce visibility is a mess otherwise.73 76 attributes.push_back( new ast::Attribute( "visibility", { 77 ast::ConstantExpr::from_string( mutDecl->location, "default" ) 78 } ) ); 79 80 // Mark as used so GCC does not warn about unused definitions 81 // in translation units that include but don't call the function. 82 attributes.push_back( new ast::Attribute( "used" ) ); 83 84 return mutDecl; 85 } 86 }; 87 88 /// Adds visibility("default") to autogen CFA autogen function definitions so they 89 /// are exported from shared libraries compiled with -fvisibility=hidden. 90 struct AutogenDefaultVisibility { 91 int funcDepth = 0; 92 93 void previsit( ast::FunctionDecl const * ) { 94 funcDepth++; 95 } 96 97 ast::FunctionDecl const * postvisit( ast::FunctionDecl const * decl ) { 98 funcDepth--; 99 // Only top-level function definitions (not nested). 100 if ( funcDepth > 0 ) return decl; 101 // Only CFA-mangled, non-builtin, non-static, non-inline functions. 102 if ( !decl->linkage.is_mangled ) return decl; 103 if ( decl->linkage.is_builtin ) return decl; 104 if ( decl->storage.is_static || decl->funcSpec.is_inline ) return decl; 105 106 // Only definitions (functions with bodies). 107 if ( !decl->stmts ) return decl; 108 109 // Only constructors, destructors, and assignment operators — 110 // the functions that cfa_linkonce autogen functions call on member types. 111 if ( !InitTweak::isDefaultConstructor( decl ) 112 && !InitTweak::isCopyConstructor( decl ) 113 && !InitTweak::isDestructor( decl ) 114 && !InitTweak::isAssignment( decl ) ) return decl; 115 116 // Skip if already has a visibility attribute. 117 auto & attributes = decl->attributes; 118 auto found = std::find_if( attributes.begin(), attributes.end(), 119 is_visibility_attribute ); 120 if ( attributes.end() != found ) return decl; 121 122 auto mutDecl = mutate( decl ); 123 mutDecl->attributes.push_back( new ast::Attribute( "visibility", { 74 124 ast::ConstantExpr::from_string( mutDecl->location, "default" ) 75 125 } ) ); … … 82 132 void translateLinkOnce( ast::TranslationUnit & translationUnit ) { 83 133 ast::Pass<LinkOnceCore>::run( translationUnit ); 134 135 // When building libcfa (-cfalib), add visibility("default") to CFA 136 // function definitions so they are exported despite -fvisibility=hidden. 137 if ( buildingLibrary() ) { 138 ast::Pass<AutogenDefaultVisibility>::run( translationUnit ); 139 } 84 140 } 85 141 -
src/Validate/Autogen.cpp
r88bb0b4 rd8a3073 352 352 replaceAll( assertions, oldToNew ); 353 353 354 bool isTopLevel = ( 0 == functionNesting ); 355 bool isCfaLinkage = getDecl()->linkage.is_mangled; 356 357 ast::Storage::Classes storage = ast::Storage::Classes(); // Default no static 358 ast::Function::Specs funcSpec; // Default no inline 359 std::vector<ast::ptr<ast::Attribute>> attributes; 360 if ( !isTopLevel ) { 361 // Nested: use inline, no linkonce needed for local types. 362 funcSpec = ast::Function::Specs( ast::Function::Inline ); 363 } else if ( isCfaLinkage ) { 364 // Top-level CFA type: use linkonce for cross-TU deduplication. 365 attributes.push_back( new ast::Attribute( "cfa_linkonce" ) ); 366 } else { 367 // Top-level C type: keep original static inline to avoid 368 // exposing latent issues in auto-generated code for system types. 369 storage = ast::Storage::Static; 370 funcSpec = ast::Function::Specs( ast::Function::Inline ); 371 } 372 354 373 ast::FunctionDecl * decl = new ast::FunctionDecl( 355 374 // Auto-generated routines use the type declaration's location. … … 362 381 // Only a prototype, no body. 363 382 nullptr, 364 // Use static storage if we are at the top level. 365 (0 < functionNesting) ? ast::Storage::Classes() : ast::Storage::Static, 383 storage, 366 384 proto_linkage, 367 std::vector<ast::ptr<ast::Attribute>>(), 368 // Auto-generated routines are inline to avoid conflicts. 369 ast::Function::Specs( ast::Function::Inline ) ); 385 std::move( attributes ), 386 funcSpec ); 370 387 decl->fixUniqueId(); 371 388 return decl; … … 401 418 add_qualifiers( dst->type, ast::CV::Qualifiers( ast::CV::Mutex ) ); 402 419 } 403 404 ast::FunctionDecl * decl = genProto( "^?{}", { dst }, {} ); 405 // For concurrent types, remove static storage and inline specifier, and add 406 // cfa_linkonce attribute so the destructor has linkonce semantics. 407 // This is required to share the same function pointer across TUs. 408 if ( isConcurrentType() ) { 409 auto mut = ast::mutate( decl ); 410 mut->storage = ast::Storage::Classes(); 411 mut->funcSpec = ast::Function::Specs(); 412 mut->attributes.push_back( new ast::Attribute( "cfa_linkonce" ) ); 413 } 414 return decl; 420 return genProto( "^?{}", { dst }, {} ); 415 421 } 416 422 … … 697 703 new ast::AddressExpr( location, 698 704 new ast::VariableExpr( location, dstParam ) ), 699 new ast::AddressExpr( location, 700 new ast::VariableExpr( location, srcParam ) ), 705 // For array types, the parameter decays to a pointer, so the 706 // variable already points to the data. For other types, take &src. 707 dynamic_cast<const ast::ArrayType *>( srcParam->type.get() ) 708 ? (ast::Expr *)new ast::CastExpr( location, 709 new ast::VariableExpr( location, srcParam ), 710 new ast::PointerType( new ast::VoidType() ) ) 711 : (ast::Expr *)new ast::AddressExpr( location, 712 new ast::VariableExpr( location, srcParam ) ), 701 713 new ast::SizeofExpr( location, srcParam->type ), 702 714 } ) );
Note:
See TracChangeset
for help on using the changeset viewer.