- Timestamp:
- Jun 21, 2023, 1:28:09 PM (2 years ago)
- Branches:
- master
- Children:
- 6065281f
- Parents:
- 2de175ce
- Location:
- src
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
src/InitTweak/GenInit.cc
r2de175ce rf02f546 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 : -
src/ResolvExpr/ResolveTypeof.h
r2de175ce rf02f546 30 30 Type *resolveTypeof( Type*, const SymTab::Indexer &indexer ); 31 31 const ast::Type * resolveTypeof( const ast::Type *, const ResolveContext & ); 32 const ast::Type * fixArrayType( const ast::Type *, const ResolveContext & ); 32 33 const ast::ObjectDecl * fixObjectType( const ast::ObjectDecl * decl , const ResolveContext & ); 33 34 } // namespace ResolvExpr -
src/ResolvExpr/Unify.cc
r2de175ce rf02f546 32 32 #include "AST/Type.hpp" 33 33 #include "AST/TypeEnvironment.hpp" 34 #include "Common/Eval.h" // for eval 34 35 #include "Common/PassVisitor.h" // for PassVisitor 35 36 #include "CommonType.hpp" // for commonType … … 779 780 } 780 781 782 // Unification of Expressions 783 // 784 // Boolean outcome (obvious): Are they basically spelled the same? 785 // Side effect of binding variables (subtle): if `sizeof(int)` ===_expr `sizeof(T)` then `int` ===_ty `T` 786 // 787 // Context: if `float[VAREXPR1]` ===_ty `float[VAREXPR2]` then `VAREXPR1` ===_expr `VAREXPR2` 788 // where the VAREXPR are meant as notational metavariables representing the fact that unification always 789 // sees distinct ast::VariableExpr objects at these positions 790 791 static bool unify( const ast::Expr * e1, const ast::Expr * e2, ast::TypeEnvironment & env, 792 ast::AssertionSet & need, ast::AssertionSet & have, const ast::OpenVarSet & open, 793 WidenMode widen ); 794 795 class UnifyExpr final : public ast::WithShortCircuiting { 796 const ast::Expr * e2; 797 ast::TypeEnvironment & tenv; 798 ast::AssertionSet & need; 799 ast::AssertionSet & have; 800 const ast::OpenVarSet & open; 801 WidenMode widen; 802 public: 803 bool result; 804 805 private: 806 807 void tryMatchOnStaticValue( const ast::Expr * e1 ) { 808 Evaluation r1 = eval(e1); 809 Evaluation r2 = eval(e2); 810 811 if ( ! r1.hasKnownValue ) return; 812 if ( ! r2.hasKnownValue ) return; 813 814 if (r1.knownValue != r2.knownValue) return; 815 816 visit_children = false; 817 result = true; 818 } 819 820 public: 821 822 void previsit( const ast::Node * ) { assert(false); } 823 824 void previsit( const ast::Expr * e1 ) { 825 tryMatchOnStaticValue( e1 ); 826 visit_children = false; 827 } 828 829 void previsit( const ast::CastExpr * e1 ) { 830 tryMatchOnStaticValue( e1 ); 831 832 if (result) { 833 assert (visit_children == false); 834 } else { 835 assert (visit_children == true); 836 visit_children = false; 837 838 auto e2c = dynamic_cast< const ast::CastExpr * >( e2 ); 839 if ( ! e2c ) return; 840 841 // inspect casts' target types 842 if ( ! unifyExact( 843 e1->result, e2c->result, tenv, need, have, open, widen ) ) return; 844 845 // inspect casts' inner expressions 846 result = unify( e1->arg, e2c->arg, tenv, need, have, open, widen ); 847 } 848 } 849 850 void previsit( const ast::VariableExpr * e1 ) { 851 tryMatchOnStaticValue( e1 ); 852 853 if (result) { 854 assert (visit_children == false); 855 } else { 856 assert (visit_children == true); 857 visit_children = false; 858 859 auto e2v = dynamic_cast< const ast::VariableExpr * >( e2 ); 860 if ( ! e2v ) return; 861 862 assert(e1->var); 863 assert(e2v->var); 864 865 // conservative: variable exprs match if their declarations are represented by the same C++ AST object 866 result = (e1->var == e2v->var); 867 } 868 } 869 870 void previsit( const ast::SizeofExpr * e1 ) { 871 tryMatchOnStaticValue( e1 ); 872 873 if (result) { 874 assert (visit_children == false); 875 } else { 876 assert (visit_children == true); 877 visit_children = false; 878 879 auto e2so = dynamic_cast< const ast::SizeofExpr * >( e2 ); 880 if ( ! e2so ) return; 881 882 assert((e1->type != nullptr) ^ (e1->expr != nullptr)); 883 assert((e2so->type != nullptr) ^ (e2so->expr != nullptr)); 884 if ( ! (e1->type && e2so->type) ) return; 885 886 // expression unification calls type unification (mutual recursion) 887 result = unifyExact( e1->type, e2so->type, tenv, need, have, open, widen ); 888 } 889 } 890 891 UnifyExpr( const ast::Expr * e2, ast::TypeEnvironment & env, ast::AssertionSet & need, 892 ast::AssertionSet & have, const ast::OpenVarSet & open, WidenMode widen ) 893 : e2( e2 ), tenv(env), need(need), have(have), open(open), widen(widen), result(false) {} 894 }; 895 896 static bool unify( const ast::Expr * e1, const ast::Expr * e2, ast::TypeEnvironment & env, 897 ast::AssertionSet & need, ast::AssertionSet & have, const ast::OpenVarSet & open, 898 WidenMode widen ) { 899 assert( e1 && e2 ); 900 return ast::Pass<UnifyExpr>::read( e1, e2, env, need, have, open, widen ); 901 } 902 781 903 class Unify_new final : public ast::WithShortCircuiting { 782 904 const ast::Type * type2; … … 820 942 if ( ! array2 ) return; 821 943 822 // to unify, array types must both be VLA or both not VLA and both must have a823 // dimension expression or not have a dimension824 944 if ( array->isVarLen != array2->isVarLen ) return; 825 if ( ! array->isVarLen && ! array2->isVarLen 826 && array->dimension && array2->dimension ) { 827 auto ce1 = array->dimension.as< ast::ConstantExpr >(); 828 auto ce2 = array2->dimension.as< ast::ConstantExpr >(); 829 830 // see C11 Reference Manual 6.7.6.2.6 831 // two array types with size specifiers that are integer constant expressions are 832 // compatible if both size specifiers have the same constant value 833 if ( ce1 && ce2 && ce1->intValue() != ce2->intValue() ) return; 945 if ( (array->dimension != nullptr) != (array2->dimension != nullptr) ) return; 946 947 if ( array->dimension ) { 948 assert( array2->dimension ); 949 // type unification calls expression unification (mutual recursion) 950 if ( ! unify(array->dimension, array2->dimension, 951 tenv, need, have, open, widen) ) return; 834 952 } 835 953 -
src/Validate/GenericParameter.cpp
r2de175ce rf02f546 16 16 #include "GenericParameter.hpp" 17 17 18 #include "AST/Copy.hpp"19 18 #include "AST/Decl.hpp" 20 19 #include "AST/Expr.hpp" … … 165 164 166 165 struct TranslateDimensionCore : 167 public WithNoIdSymbolTable, public ast::WithGuards { 166 public WithNoIdSymbolTable, public ast::WithGuards, 167 public ast::WithVisitorRef<TranslateDimensionCore> { 168 168 169 169 // SUIT: Struct- or Union- InstType … … 190 190 191 191 const ast::TypeDecl * postvisit( const ast::TypeDecl * decl ); 192 const ast::Type * postvisit( const ast::FunctionType * type ); 193 const ast::Type * postvisit( const ast::TypeInstType * type ); 194 192 195 const ast::Expr * postvisit( const ast::DimensionExpr * expr ); 193 196 const ast::Expr * postvisit( const ast::Expr * expr ); … … 195 198 }; 196 199 200 // Declaration of type variable: forall( [N] ) -> forall( N & | sized( N ) ) 197 201 const ast::TypeDecl * TranslateDimensionCore::postvisit( 198 202 const ast::TypeDecl * decl ) { … … 206 210 } 207 211 return decl; 212 } 213 214 // Makes postvisit( TypeInstType ) get called on the entries of the function declaration's type's forall list. 215 // Pass.impl.hpp's visit( FunctionType ) does not consider the forall entries to be child nodes. 216 // Workaround is: during the current TranslateDimension pass, manually visit down there. 217 const ast::Type * TranslateDimensionCore::postvisit( 218 const ast::FunctionType * type ) { 219 visitor->maybe_accept( type, &ast::FunctionType::forall ); 220 return type; 221 } 222 223 // Use of type variable, assuming `forall( [N] )` in scope: void (*)( foo( /*dimension*/ N ) & ) -> void (*)( foo( /*dtype*/ N ) & ) 224 const ast::Type * TranslateDimensionCore::postvisit( 225 const ast::TypeInstType * type ) { 226 if ( type->kind == ast::TypeDecl::Dimension ) { 227 auto mutType = ast::mutate( type ); 228 mutType->kind = ast::TypeDecl::Dtype; 229 return mutType; 230 } 231 return type; 208 232 } 209 233
Note:
See TracChangeset
for help on using the changeset viewer.