- Timestamp:
- Nov 28, 2024, 4:34:08 PM (10 months ago)
- Branches:
- master
- Children:
- 46c4dea
- Parents:
- f5e37a4
- Location:
- src
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
src/ResolvExpr/ResolveTypeof.cpp
rf5e37a4 r81e768d 88 88 FixArrayDimension(const ResolveContext & context) : context( context ) {} 89 89 90 const ast::ArrayType * previsit (const ast::ArrayType * arrayType) { 91 if (!arrayType->dimension) return arrayType; 92 auto mutType = mutate(arrayType); 90 template< typename PtrType > 91 const PtrType * previsitImpl( const PtrType * type ) { 92 // Note: resolving dimension expressions seems to require duplicate logic, 93 // here and Resolver.cpp: handlePtrType 94 95 if (!type->dimension) return type; 96 auto mutType = mutate(type); 93 97 auto globalSizeType = context.global.sizeType; 94 98 ast::ptr<ast::Type> sizetype = globalSizeType ? globalSizeType : new ast::BasicType( ast::BasicKind::LongUnsignedInt ); 95 mutType->dimension = findSingleExpression( arrayType->dimension, sizetype, context );99 mutType->dimension = findSingleExpression(type->dimension, sizetype, context ); 96 100 97 101 if (InitTweak::isConstExpr(mutType->dimension)) { … … 102 106 } 103 107 return mutType; 108 } 109 110 const ast::ArrayType * previsit (const ast::ArrayType * arrayType) { 111 return previsitImpl( arrayType ); 112 } 113 114 const ast::PointerType * previsit (const ast::PointerType * pointerType) { 115 return previsitImpl( pointerType ); 104 116 } 105 117 }; -
src/ResolvExpr/Resolver.cpp
rf5e37a4 r81e768d 494 494 } 495 495 496 // Returns a version of `ty`, with some detail redacted. 497 // `ty` is that of a parameter or return of `functionDecl`. 498 // Redaction: 499 // - concerns the dimension expression, when `ty` is a pointer or array 500 // - prevents escape of variables bound by other parameter declarations 501 // - replaces the whole dimension with `*` if it uses such a variable 502 // - produces the caller's view of `functionDecl`, where `ty` is from the callee/body's view 503 // Example 1 504 // functionDecl: void f( int n, float a[][5][n + 1] ); 505 // outcome: f : void (*)( int , float [][5][*] ), redaction on deepest ArrayType 506 // Example 2 507 // functionDecl: void f( int n, float a[n] ); 508 // outcome: f : void (*)( int , float [*] ), redaction on PointerType 509 // Example 3 510 // in scope: int n; 511 // functionDecl: void f( float a[][n] ); 512 // outcome: f : void (*)( float [][n] ), no redaction 513 static const ast::Type * redactBoundDimExprs( 514 const ast::Type * ty, 515 const ast::FunctionDecl * functionDecl 516 ); 517 struct UsesParams { 518 const ast::FunctionDecl * functionDecl; 519 UsesParams( const ast::FunctionDecl * functionDecl ) : functionDecl(functionDecl) {} 520 bool result = false; 521 void postvisit( const ast::VariableExpr * e ) { 522 for ( auto p : functionDecl->params ) { 523 if ( p.get() == e->var ) result = true; 524 } 525 } 526 }; 527 struct Redactor { 528 const ast::FunctionDecl * functionDecl; 529 Redactor( const ast::FunctionDecl * functionDecl ) : functionDecl(functionDecl) {} 530 template< typename PtrType > 531 const PtrType * postvisitImpl( const PtrType * type ) { 532 if ( type->dimension && ast::Pass<UsesParams>::read( type->dimension.get(), functionDecl ) ) { 533 // PtrType * newtype = ast::shallowCopy( type ); 534 // newtype->dimension = nullptr; 535 // type = newtype; 536 auto mutType = mutate(type); 537 mutType->dimension = nullptr; 538 type = mutType; 539 } 540 return type; 541 } 542 543 const ast::ArrayType * postvisit (const ast::ArrayType * arrayType) { 544 return postvisitImpl( arrayType ); 545 } 546 547 const ast::PointerType * postvisit (const ast::PointerType * pointerType) { 548 return postvisitImpl( pointerType ); 549 } 550 }; 551 static const ast::Type * redactBoundDimExprs( 552 const ast::Type * ty, 553 const ast::FunctionDecl * functionDecl 554 ) { 555 if ( ast::Pass<UsesParams>::read( ty, functionDecl ) ) { 556 ast::Type * newty = ast::deepCopy( ty ); 557 ast::Pass<Redactor> visitor(functionDecl); 558 ty = newty->accept(visitor); 559 } 560 return ty; 561 } 562 496 563 const ast::FunctionDecl * Resolver::previsit( const ast::FunctionDecl * functionDecl ) { 497 564 GuardValue( functionReturn ); … … 534 601 param = fixObjectType(param.strict_as<ast::ObjectDecl>(), context); 535 602 symtab.addId(param); 536 paramTypes.emplace_back(param->get_type()); 603 auto exportParamT = redactBoundDimExprs( param->get_type(), mutDecl ); 604 paramTypes.emplace_back( exportParamT ); 537 605 } 538 606 for (auto & ret : mutDecl->returns) { 539 607 ret = fixObjectType(ret.strict_as<ast::ObjectDecl>(), context); 540 returnTypes.emplace_back(ret->get_type()); 608 auto exportRetT = redactBoundDimExprs( ret->get_type(), mutDecl ); 609 returnTypes.emplace_back( exportRetT ); 541 610 } 542 611 // since function type in decl is just a view of param types, need to update that as well … … 699 768 template< typename PtrType > 700 769 const PtrType * handlePtrType( const PtrType * type, const ResolveContext & context ) { 770 // Note: resolving dimension expressions seems to require duplicate logic, 771 // here and ResolveTypeof.cpp:fixArrayType. 701 772 if ( type->dimension ) { 702 773 const ast::Type * sizeType = context.global.sizeType.get(); … … 704 775 assertf(dimension->env->empty(), "array dimension expr has nonempty env"); 705 776 dimension.get_and_mutate()->env = nullptr; 706 ast::mutate_field( type, &PtrType::dimension, dimension );777 type = ast::mutate_field( type, &PtrType::dimension, dimension ); 707 778 } 708 779 return type; -
src/ResolvExpr/Unify.cpp
rf5e37a4 r81e768d 292 292 if ( !array2 ) return; 293 293 294 if ( array->isVarLen != array2->isVarLen ) return; 295 if ( (array->dimension != nullptr) != (array2->dimension != nullptr) ) return; 296 297 if ( array->dimension ) { 294 // Permit cases where one side has a dimension or isVarLen, 295 // while the other side is the opposite. 296 // Acheves a wildcard-iterpretation semantics, where lack of 297 // dimension (`float a[]` or `float a[25][*]`) means 298 // "anything here is fine." 299 // Sole known case where a verbatim-match semantics is intended 300 // is typedef redefinition, for which extra checking is added 301 // in src/Validate/ReplaceTypedef.cpp. 302 303 if ( array->dimension && array2->dimension ) { 298 304 assert( array2->dimension ); 299 305 // type unification calls expression unification (mutual recursion) -
src/Validate/ReplaceTypedef.cpp
rf5e37a4 r81e768d 120 120 } 121 121 } 122 123 122 struct VarLenChecker : public ast::WithShortCircuiting { 124 123 bool result = false; … … 126 125 void previsit( ast::ArrayType const * at ) { result |= at->isVarLen; } 127 126 }; 128 127 static bool hasVarLen( const ast::Type * t ) { 128 return ast::Pass<VarLenChecker>::read( t ); 129 } 130 struct ArrayTypeExtractor { 131 std::vector<const ast::ArrayType *> result; 132 void postvisit( const ast::ArrayType * at ) { 133 result.push_back( at ); 134 } 135 }; 136 static bool dimensionPresenceMismatched( const ast::Type * t0, const ast::Type * t1) { 137 std::vector<const ast::ArrayType *> at0s = std::move( 138 ast::Pass<ArrayTypeExtractor>::read( t0 ) ); 139 std::vector<const ast::ArrayType *> at1s = std::move( 140 ast::Pass<ArrayTypeExtractor>::read( t1 ) ); 141 assert( at0s.size() == at1s.size() ); 142 for (size_t i = 0; i < at0s.size(); i++) { 143 const ast::ArrayType * at0 = at0s[i]; 144 const ast::ArrayType * at1 = at1s[i]; 145 assert( ResolvExpr::typesCompatible( at0, at1 ) ); 146 if ( (at0->dimension != nullptr) != (at1->dimension != nullptr) ) return true; 147 } 148 return false; 149 } 129 150 ast::Decl const * ReplaceTypedefCore::postvisit( 130 151 ast::TypedefDecl const * decl ) { … … 133 154 ast::Type const * t0 = decl->base; 134 155 ast::Type const * t1 = typedefNames[ decl->name ].first->base; 156 // [hasVarLen] 135 157 // Cannot redefine VLA typedefs. Note: this is slightly incorrect, 136 158 // because our notion of VLAs at this point in the translator is … … 139 161 // constant/enumerator. The effort required to fix this corner case 140 162 // likely outweighs the utility of allowing it. 163 // [dimensionPresenceMismatched] 164 // Core typesCompatible logic interprets absent dimensions as wildcards, 165 // i.e. float[][*] matches float[][42]. 166 // For detecting incompatible typedefs, we have to interpret them verbatim, 167 // i.e. float[] is different than float[42]. 168 // But typesCompatible does assure that the pair of types is structurally 169 // consistent, outside of the dimension expressions. This assurance guards 170 // the dimension-presence traversal. So this traversal logic can (and does) 171 // assume that ArrayTypes will be encountered in analogous places. 141 172 if ( !ResolvExpr::typesCompatible( t0, t1 ) 142 || ast::Pass<VarLenChecker>::read( t0 ) 143 || ast::Pass<VarLenChecker>::read( t1 ) ) { 173 || hasVarLen( t0 ) 174 || hasVarLen( t1 ) 175 || dimensionPresenceMismatched( t0, t1 ) ) { 144 176 SemanticError( decl->location, "Cannot redefine typedef %s", decl->name.c_str() ); 145 177 }
Note:
See TracChangeset
for help on using the changeset viewer.