- Timestamp:
- Jun 19, 2023, 1:57:11 PM (2 years ago)
- Branches:
- master
- Children:
- adc73a5
- Parents:
- fa5e1aa5 (diff), 33d4bc8 (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. - Location:
- src
- Files:
-
- 41 edited
Legend:
- Unmodified
- Added
- Removed
-
src/AST/Convert.cpp
rfa5e1aa5 rb7b3e41 2343 2343 old->location, 2344 2344 GET_ACCEPT_1(arg, Expr), 2345 old->isGenerated ? ast::GeneratedCast : ast::ExplicitCast 2345 old->isGenerated ? ast::GeneratedCast : ast::ExplicitCast, 2346 (ast::CastExpr::CastKind) old->kind 2346 2347 ) 2347 2348 ); -
src/AST/Decl.cpp
rfa5e1aa5 rb7b3e41 142 142 bool EnumDecl::valueOf( const Decl * enumerator, long long& value ) const { 143 143 if ( enumValues.empty() ) { 144 long long crntVal = 0;144 Evaluation crntVal = {0, true, true}; // until expression is given, we know to start counting from 0 145 145 for ( const Decl * member : members ) { 146 146 const ObjectDecl* field = strict_dynamic_cast< const ObjectDecl* >( member ); 147 147 if ( field->init ) { 148 148 const SingleInit * init = strict_dynamic_cast< const SingleInit* >( field->init.get() ); 149 auto result= eval( init->value );150 if ( ! result.second) {149 crntVal = eval( init->value ); 150 if ( ! crntVal.isEvaluableInGCC ) { 151 151 SemanticError( init->location, ::toString( "Non-constexpr in initialization of " 152 152 "enumerator: ", field ) ); 153 153 } 154 crntVal = result.first;155 154 } 156 155 if ( enumValues.count( field->name ) != 0 ) { 157 156 SemanticError( location, ::toString( "Enum ", name, " has multiple members with the " "name ", field->name ) ); 158 157 } 159 enumValues[ field->name ] = crntVal; 160 ++crntVal; 158 if (crntVal.hasKnownValue) { 159 enumValues[ field->name ] = crntVal.knownValue; 160 } 161 ++crntVal.knownValue; 161 162 } 162 163 } -
src/AST/DeclReplacer.hpp
rfa5e1aa5 rb7b3e41 18 18 #include <unordered_map> 19 19 20 #include "Node.hpp" 20 namespace ast { 21 class DeclWithType; 22 class Expr; 23 class Node; 24 class TypeDecl; 25 } 21 26 22 27 namespace ast { 23 class DeclWithType;24 class TypeDecl;25 class Expr;26 28 27 namespace DeclReplacer { 28 using DeclMap = std::unordered_map< const DeclWithType *, const DeclWithType * >; 29 using TypeMap = std::unordered_map< const TypeDecl *, const TypeDecl * >; 30 using ExprMap = std::unordered_map< const DeclWithType *, const Expr * >; 29 namespace DeclReplacer { 31 30 32 const Node * replace( const Node * node, const DeclMap & declMap, bool debug = false ); 33 const Node * replace( const Node * node, const TypeMap & typeMap, bool debug = false ); 34 const Node * replace( const Node * node, const DeclMap & declMap, const TypeMap & typeMap, bool debug = false ); 35 const Node * replace( const Node * node, const ExprMap & exprMap); 36 } 31 using DeclMap = std::unordered_map< const DeclWithType *, const DeclWithType * >; 32 using TypeMap = std::unordered_map< const TypeDecl *, const TypeDecl * >; 33 using ExprMap = std::unordered_map< const DeclWithType *, const Expr * >; 34 35 const Node * replace( const Node * node, const DeclMap & declMap, bool debug = false ); 36 const Node * replace( const Node * node, const TypeMap & typeMap, bool debug = false ); 37 const Node * replace( const Node * node, const DeclMap & declMap, const TypeMap & typeMap, bool debug = false ); 38 const Node * replace( const Node * node, const ExprMap & exprMap); 39 40 } 41 37 42 } 38 43 -
src/AST/Expr.cpp
rfa5e1aa5 rb7b3e41 186 186 // --- CastExpr 187 187 188 CastExpr::CastExpr( const CodeLocation & loc, const Expr * a, GeneratedFlag g )189 : Expr( loc, new VoidType{} ), arg( a ), isGenerated( g ) {}188 CastExpr::CastExpr( const CodeLocation & loc, const Expr * a, GeneratedFlag g, CastKind kind ) 189 : Expr( loc, new VoidType{} ), arg( a ), isGenerated( g ), kind( kind ) {} 190 190 191 191 bool CastExpr::get_lvalue() const { -
src/AST/Expr.hpp
rfa5e1aa5 rb7b3e41 55 55 const Expr * e ) 56 56 : decl( id ), declptr( declptr ), actualType( actual ), formalType( formal ), expr( e ) {} 57 58 operator bool() {return declptr;} 57 59 }; 58 60 … … 335 337 GeneratedFlag isGenerated; 336 338 339 enum CastKind { 340 Default, // C 341 Coerce, // reinterpret cast 342 Return // overload selection 343 }; 344 345 CastKind kind = Default; 346 337 347 CastExpr( const CodeLocation & loc, const Expr * a, const Type * to, 338 GeneratedFlag g = GeneratedCast ) : Expr( loc, to ), arg( a ), isGenerated( g) {}348 GeneratedFlag g = GeneratedCast, CastKind kind = Default ) : Expr( loc, to ), arg( a ), isGenerated( g ), kind( kind ) {} 339 349 /// Cast-to-void 340 CastExpr( const CodeLocation & loc, const Expr * a, GeneratedFlag g = GeneratedCast );350 CastExpr( const CodeLocation & loc, const Expr * a, GeneratedFlag g = GeneratedCast, CastKind kind = Default ); 341 351 342 352 /// Wrap a cast expression around an existing expression (always generated) -
src/AST/Pass.hpp
rfa5e1aa5 rb7b3e41 414 414 }; 415 415 416 /// Use when the templated visitor should update the symbol table 416 /// Use when the templated visitor should update the symbol table, 417 /// that is, when your pass core needs to query the symbol table. 418 /// Expected setups: 419 /// - For master passes that kick off at the compilation unit 420 /// - before resolver: extend WithSymbolTableX<IgnoreErrors> 421 /// - after resolver: extend WithSymbolTable and use defaults 422 /// - (FYI, for completeness, the resolver's main pass uses ValidateOnAdd when it kicks off) 423 /// - For helper passes that kick off at arbitrary points in the AST: 424 /// - take an existing symbol table as a parameter, extend WithSymbolTable, 425 /// and construct with WithSymbolTable(const SymbolTable &) 417 426 struct WithSymbolTable { 418 SymbolTable symtab; 427 WithSymbolTable(const ast::SymbolTable & from) : symtab(from) {} 428 WithSymbolTable(ast::SymbolTable::ErrorDetection errorMode = ast::SymbolTable::ErrorDetection::AssertClean) : symtab(errorMode) {} 429 ast::SymbolTable symtab; 430 }; 431 template <ast::SymbolTable::ErrorDetection errorMode> 432 struct WithSymbolTableX : WithSymbolTable { 433 WithSymbolTableX() : WithSymbolTable(errorMode) {} 419 434 }; 420 435 -
src/AST/Pass.impl.hpp
rfa5e1aa5 rb7b3e41 72 72 template<typename it_t, template <class...> class container_t> 73 73 static inline void take_all( it_t it, container_t<ast::ptr<ast::Decl>> * decls, bool * mutated = nullptr ) { 74 if (empty(decls)) return;74 if ( empty( decls ) ) return; 75 75 76 76 std::transform(decls->begin(), decls->end(), it, [](const ast::Decl * decl) -> auto { … … 78 78 }); 79 79 decls->clear(); 80 if (mutated) *mutated = true;80 if ( mutated ) *mutated = true; 81 81 } 82 82 83 83 template<typename it_t, template <class...> class container_t> 84 84 static inline void take_all( it_t it, container_t<ast::ptr<ast::Stmt>> * stmts, bool * mutated = nullptr ) { 85 if (empty(stmts)) return;85 if ( empty( stmts ) ) return; 86 86 87 87 std::move(stmts->begin(), stmts->end(), it); 88 88 stmts->clear(); 89 if (mutated) *mutated = true;89 if ( mutated ) *mutated = true; 90 90 } 91 91 … … 93 93 /// Check if should be skipped, different for pointers and containers 94 94 template<typename node_t> 95 bool skip( const ast::ptr<node_t> & val ) {95 bool skip( const ast::ptr<node_t> & val ) { 96 96 return !val; 97 97 } … … 110 110 111 111 template<typename node_t> 112 const node_t & get( const node_t & val, long ) {112 const node_t & get( const node_t & val, long ) { 113 113 return val; 114 114 } … … 126 126 } 127 127 } 128 129 template< typename core_t > 130 template< typename node_t > 131 auto ast::Pass< core_t >::call_accept( const node_t * node ) 132 -> typename ast::Pass< core_t >::template generic_call_accept_result<node_t>::type 133 { 134 __pedantic_pass_assert( __visit_children() ); 135 __pedantic_pass_assert( node ); 136 137 static_assert( !std::is_base_of<ast::Expr, node_t>::value, "ERROR"); 138 static_assert( !std::is_base_of<ast::Stmt, node_t>::value, "ERROR"); 139 140 auto nval = node->accept( *this ); 141 __pass::result1< 142 typename std::remove_pointer< decltype( node->accept(*this) ) >::type 143 > res; 144 res.differs = nval != node; 145 res.value = nval; 146 return res; 147 } 148 149 template< typename core_t > 150 __pass::template result1<ast::Expr> ast::Pass< core_t >::call_accept( const ast::Expr * expr ) { 151 __pedantic_pass_assert( __visit_children() ); 152 __pedantic_pass_assert( expr ); 153 154 auto nval = expr->accept( *this ); 155 return { nval != expr, nval }; 156 } 157 158 template< typename core_t > 159 __pass::template result1<ast::Stmt> ast::Pass< core_t >::call_accept( const ast::Stmt * stmt ) { 160 __pedantic_pass_assert( __visit_children() ); 161 __pedantic_pass_assert( stmt ); 162 163 const ast::Stmt * nval = stmt->accept( *this ); 164 return { nval != stmt, nval }; 165 } 166 167 template< typename core_t > 168 __pass::template result1<ast::Expr> ast::Pass< core_t >::call_accept_top( const ast::Expr * expr ) { 169 __pedantic_pass_assert( __visit_children() ); 170 __pedantic_pass_assert( expr ); 171 172 const ast::TypeSubstitution ** typeSubs_ptr = __pass::typeSubs( core, 0 ); 173 if ( typeSubs_ptr && expr->env ) { 174 *typeSubs_ptr = expr->env; 175 } 176 177 auto nval = expr->accept( *this ); 178 return { nval != expr, nval }; 179 } 180 181 template< typename core_t > 182 __pass::template result1<ast::Stmt> ast::Pass< core_t >::call_accept_as_compound( const ast::Stmt * stmt ) { 183 __pedantic_pass_assert( __visit_children() ); 184 __pedantic_pass_assert( stmt ); 185 186 // add a few useful symbols to the scope 187 using __pass::empty; 188 189 // get the stmts/decls that will need to be spliced in 190 auto stmts_before = __pass::stmtsToAddBefore( core, 0 ); 191 auto stmts_after = __pass::stmtsToAddAfter ( core, 0 ); 192 auto decls_before = __pass::declsToAddBefore( core, 0 ); 193 auto decls_after = __pass::declsToAddAfter ( core, 0 ); 194 195 // These may be modified by subnode but most be restored once we exit this statemnet. 196 ValueGuardPtr< const ast::TypeSubstitution * > __old_env ( __pass::typeSubs( core, 0 ) ); 197 ValueGuardPtr< typename std::remove_pointer< decltype(stmts_before) >::type > __old_decls_before( stmts_before ); 198 ValueGuardPtr< typename std::remove_pointer< decltype(stmts_after ) >::type > __old_decls_after ( stmts_after ); 199 ValueGuardPtr< typename std::remove_pointer< decltype(decls_before) >::type > __old_stmts_before( decls_before ); 200 ValueGuardPtr< typename std::remove_pointer< decltype(decls_after ) >::type > __old_stmts_after ( decls_after ); 201 202 // Now is the time to actually visit the node 203 const ast::Stmt * nstmt = stmt->accept( *this ); 204 205 // If the pass doesn't want to add anything then we are done 206 if( empty(stmts_before) && empty(stmts_after) && empty(decls_before) && empty(decls_after) ) { 207 return { nstmt != stmt, nstmt }; 208 } 209 210 // Make sure that it is either adding statements or declartions but not both 211 // this is because otherwise the order would be awkward to predict 212 assert(( empty( stmts_before ) && empty( stmts_after )) 213 || ( empty( decls_before ) && empty( decls_after )) ); 214 215 // Create a new Compound Statement to hold the new decls/stmts 216 ast::CompoundStmt * compound = new ast::CompoundStmt( stmt->location ); 217 218 // Take all the declarations that go before 219 __pass::take_all( std::back_inserter( compound->kids ), decls_before ); 220 __pass::take_all( std::back_inserter( compound->kids ), stmts_before ); 221 222 // Insert the original declaration 223 compound->kids.emplace_back( nstmt ); 224 225 // Insert all the declarations that go before 226 __pass::take_all( std::back_inserter( compound->kids ), decls_after ); 227 __pass::take_all( std::back_inserter( compound->kids ), stmts_after ); 228 229 return {true, compound}; 230 } 231 232 template< typename core_t > 233 template< template <class...> class container_t > 234 __pass::template resultNstmt<container_t> ast::Pass< core_t >::call_accept( const container_t< ptr<Stmt> > & statements ) { 235 __pedantic_pass_assert( __visit_children() ); 236 if( statements.empty() ) return {}; 237 238 // We are going to aggregate errors for all these statements 239 SemanticErrorException errors; 240 241 // add a few useful symbols to the scope 242 using __pass::empty; 243 244 // get the stmts/decls that will need to be spliced in 245 auto stmts_before = __pass::stmtsToAddBefore( core, 0 ); 246 auto stmts_after = __pass::stmtsToAddAfter ( core, 0 ); 247 auto decls_before = __pass::declsToAddBefore( core, 0 ); 248 auto decls_after = __pass::declsToAddAfter ( core, 0 ); 249 250 // These may be modified by subnode but most be restored once we exit this statemnet. 251 ValueGuardPtr< typename std::remove_pointer< decltype(stmts_before) >::type > __old_decls_before( stmts_before ); 252 ValueGuardPtr< typename std::remove_pointer< decltype(stmts_after ) >::type > __old_decls_after ( stmts_after ); 253 ValueGuardPtr< typename std::remove_pointer< decltype(decls_before) >::type > __old_stmts_before( decls_before ); 254 ValueGuardPtr< typename std::remove_pointer< decltype(decls_after ) >::type > __old_stmts_after ( decls_after ); 255 256 // update pass statitistics 257 pass_visitor_stats.depth++; 258 pass_visitor_stats.max->push(pass_visitor_stats.depth); 259 pass_visitor_stats.avg->push(pass_visitor_stats.depth); 260 261 __pass::resultNstmt<container_t> new_kids; 262 for( auto value : enumerate( statements ) ) { 263 try { 264 size_t i = value.idx; 265 const Stmt * stmt = value.val; 266 __pedantic_pass_assert( stmt ); 267 const ast::Stmt * new_stmt = stmt->accept( *this ); 268 assert( new_stmt ); 269 if(new_stmt != stmt ) { new_kids.differs = true; } 270 271 // Make sure that it is either adding statements or declartions but not both 272 // this is because otherwise the order would be awkward to predict 273 assert(( empty( stmts_before ) && empty( stmts_after )) 274 || ( empty( decls_before ) && empty( decls_after )) ); 275 276 // Take all the statements which should have gone after, N/A for first iteration 277 new_kids.take_all( decls_before ); 278 new_kids.take_all( stmts_before ); 279 280 // Now add the statement if there is one 281 if(new_stmt != stmt) { 282 new_kids.values.emplace_back( new_stmt, i, false ); 283 } else { 284 new_kids.values.emplace_back( nullptr, i, true ); 285 } 286 287 // Take all the declarations that go before 288 new_kids.take_all( decls_after ); 289 new_kids.take_all( stmts_after ); 128 } 129 130 template< typename core_t > 131 template< typename node_t > 132 auto ast::Pass< core_t >::call_accept( const node_t * node ) -> 133 typename ast::Pass< core_t >::template generic_call_accept_result<node_t>::type 134 { 135 __pedantic_pass_assert( __visit_children() ); 136 __pedantic_pass_assert( node ); 137 138 static_assert( !std::is_base_of<ast::Expr, node_t>::value, "ERROR" ); 139 static_assert( !std::is_base_of<ast::Stmt, node_t>::value, "ERROR" ); 140 141 auto nval = node->accept( *this ); 142 __pass::result1< 143 typename std::remove_pointer< decltype( node->accept(*this) ) >::type 144 > res; 145 res.differs = nval != node; 146 res.value = nval; 147 return res; 148 } 149 150 template< typename core_t > 151 ast::__pass::template result1<ast::Expr> ast::Pass< core_t >::call_accept( const ast::Expr * expr ) { 152 __pedantic_pass_assert( __visit_children() ); 153 __pedantic_pass_assert( expr ); 154 155 auto nval = expr->accept( *this ); 156 return { nval != expr, nval }; 157 } 158 159 template< typename core_t > 160 ast::__pass::template result1<ast::Stmt> ast::Pass< core_t >::call_accept( const ast::Stmt * stmt ) { 161 __pedantic_pass_assert( __visit_children() ); 162 __pedantic_pass_assert( stmt ); 163 164 const ast::Stmt * nval = stmt->accept( *this ); 165 return { nval != stmt, nval }; 166 } 167 168 template< typename core_t > 169 ast::__pass::template result1<ast::Expr> ast::Pass< core_t >::call_accept_top( const ast::Expr * expr ) { 170 __pedantic_pass_assert( __visit_children() ); 171 __pedantic_pass_assert( expr ); 172 173 const ast::TypeSubstitution ** typeSubs_ptr = __pass::typeSubs( core, 0 ); 174 if ( typeSubs_ptr && expr->env ) { 175 *typeSubs_ptr = expr->env; 176 } 177 178 auto nval = expr->accept( *this ); 179 return { nval != expr, nval }; 180 } 181 182 template< typename core_t > 183 ast::__pass::template result1<ast::Stmt> ast::Pass< core_t >::call_accept_as_compound( const ast::Stmt * stmt ) { 184 __pedantic_pass_assert( __visit_children() ); 185 __pedantic_pass_assert( stmt ); 186 187 // add a few useful symbols to the scope 188 using __pass::empty; 189 190 // get the stmts/decls that will need to be spliced in 191 auto stmts_before = __pass::stmtsToAddBefore( core, 0 ); 192 auto stmts_after = __pass::stmtsToAddAfter ( core, 0 ); 193 auto decls_before = __pass::declsToAddBefore( core, 0 ); 194 auto decls_after = __pass::declsToAddAfter ( core, 0 ); 195 196 // These may be modified by subnode but most be restored once we exit this statemnet. 197 ValueGuardPtr< const ast::TypeSubstitution * > __old_env ( __pass::typeSubs( core, 0 ) ); 198 ValueGuardPtr< typename std::remove_pointer< decltype(stmts_before) >::type > __old_decls_before( stmts_before ); 199 ValueGuardPtr< typename std::remove_pointer< decltype(stmts_after ) >::type > __old_decls_after ( stmts_after ); 200 ValueGuardPtr< typename std::remove_pointer< decltype(decls_before) >::type > __old_stmts_before( decls_before ); 201 ValueGuardPtr< typename std::remove_pointer< decltype(decls_after ) >::type > __old_stmts_after ( decls_after ); 202 203 // Now is the time to actually visit the node 204 const ast::Stmt * nstmt = stmt->accept( *this ); 205 206 // If the pass doesn't want to add anything then we are done 207 if ( empty(stmts_before) && empty(stmts_after) && empty(decls_before) && empty(decls_after) ) { 208 return { nstmt != stmt, nstmt }; 209 } 210 211 // Make sure that it is either adding statements or declartions but not both 212 // this is because otherwise the order would be awkward to predict 213 assert(( empty( stmts_before ) && empty( stmts_after )) 214 || ( empty( decls_before ) && empty( decls_after )) ); 215 216 // Create a new Compound Statement to hold the new decls/stmts 217 ast::CompoundStmt * compound = new ast::CompoundStmt( stmt->location ); 218 219 // Take all the declarations that go before 220 __pass::take_all( std::back_inserter( compound->kids ), decls_before ); 221 __pass::take_all( std::back_inserter( compound->kids ), stmts_before ); 222 223 // Insert the original declaration 224 compound->kids.emplace_back( nstmt ); 225 226 // Insert all the declarations that go before 227 __pass::take_all( std::back_inserter( compound->kids ), decls_after ); 228 __pass::take_all( std::back_inserter( compound->kids ), stmts_after ); 229 230 return { true, compound }; 231 } 232 233 template< typename core_t > 234 template< template <class...> class container_t > 235 ast::__pass::template resultNstmt<container_t> ast::Pass< core_t >::call_accept( const container_t< ptr<Stmt> > & statements ) { 236 __pedantic_pass_assert( __visit_children() ); 237 if ( statements.empty() ) return {}; 238 239 // We are going to aggregate errors for all these statements 240 SemanticErrorException errors; 241 242 // add a few useful symbols to the scope 243 using __pass::empty; 244 245 // get the stmts/decls that will need to be spliced in 246 auto stmts_before = __pass::stmtsToAddBefore( core, 0 ); 247 auto stmts_after = __pass::stmtsToAddAfter ( core, 0 ); 248 auto decls_before = __pass::declsToAddBefore( core, 0 ); 249 auto decls_after = __pass::declsToAddAfter ( core, 0 ); 250 251 // These may be modified by subnode but most be restored once we exit this statemnet. 252 ValueGuardPtr< typename std::remove_pointer< decltype(stmts_before) >::type > __old_decls_before( stmts_before ); 253 ValueGuardPtr< typename std::remove_pointer< decltype(stmts_after ) >::type > __old_decls_after ( stmts_after ); 254 ValueGuardPtr< typename std::remove_pointer< decltype(decls_before) >::type > __old_stmts_before( decls_before ); 255 ValueGuardPtr< typename std::remove_pointer< decltype(decls_after ) >::type > __old_stmts_after ( decls_after ); 256 257 // update pass statitistics 258 pass_visitor_stats.depth++; 259 pass_visitor_stats.max->push(pass_visitor_stats.depth); 260 pass_visitor_stats.avg->push(pass_visitor_stats.depth); 261 262 __pass::resultNstmt<container_t> new_kids; 263 for ( auto value : enumerate( statements ) ) { 264 try { 265 size_t i = value.idx; 266 const Stmt * stmt = value.val; 267 __pedantic_pass_assert( stmt ); 268 const ast::Stmt * new_stmt = stmt->accept( *this ); 269 assert( new_stmt ); 270 if ( new_stmt != stmt ) { new_kids.differs = true; } 271 272 // Make sure that it is either adding statements or declartions but not both 273 // this is because otherwise the order would be awkward to predict 274 assert(( empty( stmts_before ) && empty( stmts_after )) 275 || ( empty( decls_before ) && empty( decls_after )) ); 276 277 // Take all the statements which should have gone after, N/A for first iteration 278 new_kids.take_all( decls_before ); 279 new_kids.take_all( stmts_before ); 280 281 // Now add the statement if there is one 282 if ( new_stmt != stmt ) { 283 new_kids.values.emplace_back( new_stmt, i, false ); 284 } else { 285 new_kids.values.emplace_back( nullptr, i, true ); 290 286 } 291 catch ( SemanticErrorException &e ) { 292 errors.append( e ); 287 288 // Take all the declarations that go before 289 new_kids.take_all( decls_after ); 290 new_kids.take_all( stmts_after ); 291 } catch ( SemanticErrorException &e ) { 292 errors.append( e ); 293 } 294 } 295 pass_visitor_stats.depth--; 296 if ( !errors.isEmpty() ) { throw errors; } 297 298 return new_kids; 299 } 300 301 template< typename core_t > 302 template< template <class...> class container_t, typename node_t > 303 ast::__pass::template resultN<container_t, node_t> ast::Pass< core_t >::call_accept( const container_t< ast::ptr<node_t> > & container ) { 304 __pedantic_pass_assert( __visit_children() ); 305 if ( container.empty() ) return {}; 306 SemanticErrorException errors; 307 308 pass_visitor_stats.depth++; 309 pass_visitor_stats.max->push(pass_visitor_stats.depth); 310 pass_visitor_stats.avg->push(pass_visitor_stats.depth); 311 312 bool mutated = false; 313 container_t<ptr<node_t>> new_kids; 314 for ( const node_t * node : container ) { 315 try { 316 __pedantic_pass_assert( node ); 317 const node_t * new_stmt = strict_dynamic_cast< const node_t * >( node->accept( *this ) ); 318 if ( new_stmt != node ) { 319 mutated = true; 320 new_kids.emplace_back( new_stmt ); 321 } else { 322 new_kids.emplace_back( nullptr ); 293 323 } 294 } 295 pass_visitor_stats.depth--; 296 if ( !errors.isEmpty() ) { throw errors; } 297 298 return new_kids; 299 } 300 301 template< typename core_t > 302 template< template <class...> class container_t, typename node_t > 303 __pass::template resultN<container_t, node_t> ast::Pass< core_t >::call_accept( const container_t< ast::ptr<node_t> > & container ) { 304 __pedantic_pass_assert( __visit_children() ); 305 if( container.empty() ) return {}; 306 SemanticErrorException errors; 307 308 pass_visitor_stats.depth++; 309 pass_visitor_stats.max->push(pass_visitor_stats.depth); 310 pass_visitor_stats.avg->push(pass_visitor_stats.depth); 311 312 bool mutated = false; 313 container_t<ptr<node_t>> new_kids; 314 for ( const node_t * node : container ) { 315 try { 316 __pedantic_pass_assert( node ); 317 const node_t * new_stmt = strict_dynamic_cast< const node_t * >( node->accept( *this ) ); 318 if(new_stmt != node ) { 319 mutated = true; 320 new_kids.emplace_back( new_stmt ); 321 } else { 322 new_kids.emplace_back( nullptr ); 323 } 324 325 } 326 catch( SemanticErrorException &e ) { 327 errors.append( e ); 328 } 329 } 330 331 __pedantic_pass_assert( new_kids.size() == container.size() ); 332 pass_visitor_stats.depth--; 333 if ( ! errors.isEmpty() ) { throw errors; } 334 335 return ast::__pass::resultN<container_t, node_t>{ mutated, new_kids }; 336 } 337 338 template< typename core_t > 339 template<typename node_t, typename super_t, typename field_t> 340 void ast::Pass< core_t >::maybe_accept( 341 const node_t * & parent, 342 field_t super_t::*field 343 ) { 344 static_assert( std::is_base_of<super_t, node_t>::value, "Error deducing member object" ); 345 346 if(__pass::skip(parent->*field)) return; 347 const auto & old_val = __pass::get(parent->*field, 0); 348 349 static_assert( !std::is_same<const ast::Node * &, decltype(old_val)>::value, "ERROR"); 350 351 auto new_val = call_accept( old_val ); 352 353 static_assert( !std::is_same<const ast::Node *, decltype(new_val)>::value /* || std::is_same<int, decltype(old_val)>::value */, "ERROR"); 354 355 if( new_val.differs ) { 356 auto new_parent = __pass::mutate<core_t>(parent); 357 new_val.apply(new_parent, field); 358 parent = new_parent; 359 } 360 } 361 362 template< typename core_t > 363 template<typename node_t, typename super_t, typename field_t> 364 void ast::Pass< core_t >::maybe_accept_top( 365 const node_t * & parent, 366 field_t super_t::*field 367 ) { 368 static_assert( std::is_base_of<super_t, node_t>::value, "Error deducing member object" ); 369 370 if(__pass::skip(parent->*field)) return; 371 const auto & old_val = __pass::get(parent->*field, 0); 372 373 static_assert( !std::is_same<const ast::Node * &, decltype(old_val)>::value, "ERROR"); 374 375 auto new_val = call_accept_top( old_val ); 376 377 static_assert( !std::is_same<const ast::Node *, decltype(new_val)>::value /* || std::is_same<int, decltype(old_val)>::value */, "ERROR"); 378 379 if( new_val.differs ) { 380 auto new_parent = __pass::mutate<core_t>(parent); 381 new_val.apply(new_parent, field); 382 parent = new_parent; 383 } 384 } 385 386 template< typename core_t > 387 template<typename node_t, typename super_t, typename field_t> 388 void ast::Pass< core_t >::maybe_accept_as_compound( 389 const node_t * & parent, 390 field_t super_t::*child 391 ) { 392 static_assert( std::is_base_of<super_t, node_t>::value, "Error deducing member object" ); 393 394 if(__pass::skip(parent->*child)) return; 395 const auto & old_val = __pass::get(parent->*child, 0); 396 397 static_assert( !std::is_same<const ast::Node * &, decltype(old_val)>::value, "ERROR"); 398 399 auto new_val = call_accept_as_compound( old_val ); 400 401 static_assert( !std::is_same<const ast::Node *, decltype(new_val)>::value || std::is_same<int, decltype(old_val)>::value, "ERROR"); 402 403 if( new_val.differs ) { 404 auto new_parent = __pass::mutate<core_t>(parent); 405 new_val.apply( new_parent, child ); 406 parent = new_parent; 407 } 408 } 409 324 } catch ( SemanticErrorException &e ) { 325 errors.append( e ); 326 } 327 } 328 329 __pedantic_pass_assert( new_kids.size() == container.size() ); 330 pass_visitor_stats.depth--; 331 if ( !errors.isEmpty() ) { throw errors; } 332 333 return ast::__pass::resultN<container_t, node_t>{ mutated, new_kids }; 334 } 335 336 template< typename core_t > 337 template<typename node_t, typename super_t, typename field_t> 338 void ast::Pass< core_t >::maybe_accept( 339 const node_t * & parent, 340 field_t super_t::*field 341 ) { 342 static_assert( std::is_base_of<super_t, node_t>::value, "Error deducing member object" ); 343 344 if ( __pass::skip( parent->*field ) ) return; 345 const auto & old_val = __pass::get(parent->*field, 0); 346 347 static_assert( !std::is_same<const ast::Node * &, decltype(old_val)>::value, "ERROR" ); 348 349 auto new_val = call_accept( old_val ); 350 351 static_assert( !std::is_same<const ast::Node *, decltype(new_val)>::value /* || std::is_same<int, decltype(old_val)>::value */, "ERROR" ); 352 353 if ( new_val.differs ) { 354 auto new_parent = __pass::mutate<core_t>(parent); 355 new_val.apply(new_parent, field); 356 parent = new_parent; 357 } 358 } 359 360 template< typename core_t > 361 template<typename node_t, typename super_t, typename field_t> 362 void ast::Pass< core_t >::maybe_accept_top( 363 const node_t * & parent, 364 field_t super_t::*field 365 ) { 366 static_assert( std::is_base_of<super_t, node_t>::value, "Error deducing member object" ); 367 368 if ( __pass::skip( parent->*field ) ) return; 369 const auto & old_val = __pass::get(parent->*field, 0); 370 371 static_assert( !std::is_same<const ast::Node * &, decltype(old_val)>::value, "ERROR" ); 372 373 auto new_val = call_accept_top( old_val ); 374 375 static_assert( !std::is_same<const ast::Node *, decltype(new_val)>::value /* || std::is_same<int, decltype(old_val)>::value */, "ERROR" ); 376 377 if ( new_val.differs ) { 378 auto new_parent = __pass::mutate<core_t>(parent); 379 new_val.apply(new_parent, field); 380 parent = new_parent; 381 } 382 } 383 384 template< typename core_t > 385 template<typename node_t, typename super_t, typename field_t> 386 void ast::Pass< core_t >::maybe_accept_as_compound( 387 const node_t * & parent, 388 field_t super_t::*child 389 ) { 390 static_assert( std::is_base_of<super_t, node_t>::value, "Error deducing member object" ); 391 392 if ( __pass::skip( parent->*child ) ) return; 393 const auto & old_val = __pass::get(parent->*child, 0); 394 395 static_assert( !std::is_same<const ast::Node * &, decltype(old_val)>::value, "ERROR" ); 396 397 auto new_val = call_accept_as_compound( old_val ); 398 399 static_assert( !std::is_same<const ast::Node *, decltype(new_val)>::value || std::is_same<int, decltype(old_val)>::value, "ERROR" ); 400 401 if ( new_val.differs ) { 402 auto new_parent = __pass::mutate<core_t>(parent); 403 new_val.apply( new_parent, child ); 404 parent = new_parent; 405 } 410 406 } 411 407 … … 761 757 762 758 if ( __visit_children() ) { 763 // Do not enter (or leave) a new scope if atFunctionTop. Remember to save the result. 764 auto guard1 = makeFuncGuard( [this, enterScope = !this->atFunctionTop]() { 765 if ( enterScope ) { 766 __pass::symtab::enter(core, 0); 767 } 768 }, [this, leaveScope = !this->atFunctionTop]() { 769 if ( leaveScope ) { 770 __pass::symtab::leave(core, 0); 771 } 772 }); 773 ValueGuard< bool > guard2( atFunctionTop ); 774 atFunctionTop = false; 775 guard_scope guard3 { *this }; 776 maybe_accept( node, &CompoundStmt::kids ); 759 // Do not enter (or leave) a new symbol table scope if atFunctionTop. 760 // But always enter (and leave) a new general scope. 761 if ( atFunctionTop ) { 762 ValueGuard< bool > guard1( atFunctionTop ); 763 atFunctionTop = false; 764 guard_scope guard2( *this ); 765 maybe_accept( node, &CompoundStmt::kids ); 766 } else { 767 guard_symtab guard1( *this ); 768 guard_scope guard2( *this ); 769 maybe_accept( node, &CompoundStmt::kids ); 770 } 777 771 } 778 772 -
src/AST/SymbolTable.cpp
rfa5e1aa5 rb7b3e41 19 19 20 20 #include "Copy.hpp" 21 #include <iostream> 22 #include <algorithm> 23 21 24 #include "Decl.hpp" 22 25 #include "Expr.hpp" … … 88 91 } 89 92 90 SymbolTable::SymbolTable( )93 SymbolTable::SymbolTable( ErrorDetection errorMode ) 91 94 : idTable(), typeTable(), structTable(), enumTable(), unionTable(), traitTable(), 92 prevScope(), scope( 0 ), repScope( 0 ) { ++*stats().count; }95 prevScope(), scope( 0 ), repScope( 0 ), errorMode(errorMode) { ++*stats().count; } 93 96 94 97 SymbolTable::~SymbolTable() { stats().size->push( idTable ? idTable->size() : 0 ); } 98 99 void SymbolTable::OnFindError( CodeLocation location, std::string error ) const { 100 assertf( errorMode != AssertClean, "Name collision/redefinition, found during a compilation phase where none should be possible. Detail: %s", error.c_str() ); 101 if (errorMode == ValidateOnAdd) { 102 SemanticError(location, error); 103 } 104 assertf( errorMode == IgnoreErrors, "Unrecognized symbol-table error mode %d", errorMode ); 105 } 95 106 96 107 void SymbolTable::enterScope() { … … 195 206 out.push_back(decl.second); 196 207 } 208 209 // std::cerr << otypeKey << ' ' << out.size() << std::endl; 197 210 } 198 211 … … 269 282 } 270 283 271 namespace { 272 /// true if redeclaration conflict between two types 273 bool addedTypeConflicts( const NamedTypeDecl * existing, const NamedTypeDecl * added ) { 274 if ( existing->base == nullptr ) { 275 return false; 276 } else if ( added->base == nullptr ) { 277 return true; 278 } else { 279 // typedef redeclarations are errors only if types are different 280 if ( ! ResolvExpr::typesCompatible( existing->base, added->base ) ) { 281 SemanticError( added->location, "redeclaration of " + added->name ); 282 } 283 } 284 // does not need to be added to the table if both existing and added have a base that are 285 // the same 284 bool SymbolTable::addedTypeConflicts( 285 const NamedTypeDecl * existing, const NamedTypeDecl * added ) const { 286 if ( existing->base == nullptr ) { 287 return false; 288 } else if ( added->base == nullptr ) { 286 289 return true; 287 } 288 289 /// true if redeclaration conflict between two aggregate declarations 290 bool addedDeclConflicts( const AggregateDecl * existing, const AggregateDecl * added ) { 291 if ( ! existing->body ) { 292 return false; 293 } else if ( added->body ) { 294 SemanticError( added, "redeclaration of " ); 295 } 296 return true; 297 } 290 } else { 291 // typedef redeclarations are errors only if types are different 292 if ( ! ResolvExpr::typesCompatible( existing->base, added->base ) ) { 293 OnFindError( added->location, "redeclaration of " + added->name ); 294 } 295 } 296 // does not need to be added to the table if both existing and added have a base that are 297 // the same 298 return true; 299 } 300 301 bool SymbolTable::addedDeclConflicts( 302 const AggregateDecl * existing, const AggregateDecl * added ) const { 303 if ( ! existing->body ) { 304 return false; 305 } else if ( added->body ) { 306 OnFindError( added, "redeclaration of " ); 307 } 308 return true; 298 309 } 299 310 … … 648 659 if ( deleter && ! existing.deleter ) { 649 660 if ( handleConflicts.mode == OnConflict::Error ) { 650 SemanticError( added, "deletion of defined identifier " );661 OnFindError( added, "deletion of defined identifier " ); 651 662 } 652 663 return true; 653 664 } else if ( ! deleter && existing.deleter ) { 654 665 if ( handleConflicts.mode == OnConflict::Error ) { 655 SemanticError( added, "definition of deleted identifier " );666 OnFindError( added, "definition of deleted identifier " ); 656 667 } 657 668 return true; … … 661 672 if ( isDefinition( added ) && isDefinition( existing.id ) ) { 662 673 if ( handleConflicts.mode == OnConflict::Error ) { 663 SemanticError( added,674 OnFindError( added, 664 675 isFunction( added ) ? 665 676 "duplicate function definition for " : … … 670 681 } else { 671 682 if ( handleConflicts.mode == OnConflict::Error ) { 672 SemanticError( added, "duplicate definition for " );683 OnFindError( added, "duplicate definition for " ); 673 684 } 674 685 return true; … … 722 733 // Check that a Cforall declaration doesn't override any C declaration 723 734 if ( hasCompatibleCDecl( name, mangleName ) ) { 724 SemanticError( decl, "Cforall declaration hides C function " );735 OnFindError( decl, "Cforall declaration hides C function " ); 725 736 } 726 737 } else { … … 728 739 // type-compatibility, which it may not be. 729 740 if ( hasIncompatibleCDecl( name, mangleName ) ) { 730 SemanticError( decl, "conflicting overload of C function " );741 OnFindError( decl, "conflicting overload of C function " ); 731 742 } 732 743 } -
src/AST/SymbolTable.hpp
rfa5e1aa5 rb7b3e41 93 93 94 94 public: 95 SymbolTable(); 95 96 /// Mode to control when (during which pass) user-caused name-declaration errors get reported. 97 /// The default setting `AssertClean` supports, "I expect all user-caused errors to have been 98 /// reported by now," or, "I wouldn't know what to do with an error; are there even any here?" 99 enum ErrorDetection { 100 AssertClean, ///< invalid user decls => assert fails during addFoo (default) 101 ValidateOnAdd, ///< invalid user decls => calls SemanticError during addFoo 102 IgnoreErrors ///< acts as if unspecified decls were removed, forcing validity 103 }; 104 105 explicit SymbolTable( 106 ErrorDetection ///< mode for the lifetime of the symbol table (whole pass) 107 ); 108 SymbolTable() : SymbolTable(AssertClean) {} 96 109 ~SymbolTable(); 110 111 ErrorDetection getErrorMode() const { 112 return errorMode; 113 } 97 114 98 115 // when using an indexer manually (e.g., within a mutator traversal), it is necessary to … … 158 175 159 176 private: 177 void OnFindError( CodeLocation location, std::string error ) const; 178 179 template< typename T > 180 void OnFindError( const T * obj, const std::string & error ) const { 181 OnFindError( obj->location, toString( error, obj ) ); 182 } 183 184 template< typename T > 185 void OnFindError( CodeLocation location, const T * obj, const std::string & error ) const { 186 OnFindError( location, toString( error, obj ) ); 187 } 188 160 189 /// Ensures that a proper backtracking scope exists before a mutation 161 190 void lazyInitScope(); … … 168 197 bool removeSpecialOverrides( IdData & decl, MangleTable::Ptr & mangleTable ); 169 198 170 /// Options for handling identifier conflicts 199 /// Error detection mode given at construction (pass-specific). 200 /// Logically const, except that the symbol table's push-pop is achieved by autogenerated 201 /// assignment onto self. The feield is left motuable to keep this code-gen simple. 202 /// Conceptual constness is preserved by all SymbolTable in a stack sharing the same mode. 203 ErrorDetection errorMode; 204 205 /// Options for handling identifier conflicts. 206 /// Varies according to AST location during traversal: captures semantics of the construct 207 /// being visited as "would shadow" vs "must not collide." 208 /// At a given AST location, is the same for every pass. 171 209 struct OnConflict { 172 210 enum { 173 Error, ///< Throw a semantic error211 Error, ///< Follow the current pass's ErrorDetection mode (may throw a semantic error) 174 212 Delete ///< Delete the earlier version with the delete statement 175 213 } mode; … … 191 229 const Decl * deleter ); 192 230 231 /// true if redeclaration conflict between two types 232 bool addedTypeConflicts( const NamedTypeDecl * existing, const NamedTypeDecl * added ) const; 233 234 /// true if redeclaration conflict between two aggregate declarations 235 bool addedDeclConflicts( const AggregateDecl * existing, const AggregateDecl * added ) const; 236 193 237 /// common code for addId, addDeletedId, etc. 194 238 void addIdCommon( … … 213 257 } 214 258 259 215 260 // Local Variables: // 216 261 // tab-width: 4 // -
src/AST/Type.hpp
rfa5e1aa5 rb7b3e41 451 451 bool operator==(const TypeEnvKey & other) const; 452 452 bool operator<(const TypeEnvKey & other) const; 453 }; 453 operator bool() {return base;} 454 }; 455 454 456 455 457 /// tuple type e.g. `[int, char]` -
src/AST/TypeEnvironment.cpp
rfa5e1aa5 rb7b3e41 135 135 } 136 136 } 137 sub.normalize();137 // sub.normalize(); 138 138 } 139 139 -
src/AST/TypeEnvironment.hpp
rfa5e1aa5 rb7b3e41 63 63 64 64 int cmp = d1->var->name.compare( d2->var->name ); 65 return cmp <0 || ( cmp == 0 && d1->result < d2->result );65 return cmp > 0 || ( cmp == 0 && d1->result < d2->result ); 66 66 } 67 67 }; -
src/AST/Util.cpp
rfa5e1aa5 rb7b3e41 83 83 } 84 84 85 /// Check that the MemberExpr has an aggregate type and matching member. 86 void memberMatchesAggregate( const MemberExpr * expr ) { 87 const Type * aggrType = expr->aggregate->result->stripReferences(); 88 const AggregateDecl * decl = nullptr; 89 if ( auto inst = dynamic_cast<const StructInstType *>( aggrType ) ) { 90 decl = inst->base; 91 } else if ( auto inst = dynamic_cast<const UnionInstType *>( aggrType ) ) { 92 decl = inst->base; 93 } 94 assertf( decl, "Aggregate of member not correct type." ); 95 96 for ( auto aggrMember : decl->members ) { 97 if ( expr->member == aggrMember ) { 98 return; 99 } 100 } 101 assertf( false, "Member not found." ); 102 } 103 85 104 struct InvariantCore { 86 105 // To save on the number of visits: this is a kind of composed core. … … 108 127 } 109 128 129 void previsit( const MemberExpr * node ) { 130 previsit( (const ParseNode *)node ); 131 memberMatchesAggregate( node ); 132 } 133 110 134 void postvisit( const Node * node ) { 111 135 no_strong_cycles.postvisit( node ); -
src/Common/Eval.cc
rfa5e1aa5 rb7b3e41 96 96 // New AST 97 97 struct EvalNew : public ast::WithShortCircuiting { 98 long long int value = 0; // compose the result of the constant expression 99 bool valid = true; // true => constant expression and value is the result 100 // false => not constant expression, e.g., ++i 101 bool cfavalid = true; // true => constant expression and value computable 102 // false => constant expression but value not computable, e.g., sizeof(int) 98 Evaluation result = { 0, true, true }; 103 99 104 100 void previsit( const ast::Node * ) { visit_children = false; } 105 void postvisit( const ast::Node * ) { cfavalid = valid= false; }101 void postvisit( const ast::Node * ) { result.isEvaluableInGCC = result.hasKnownValue = false; } 106 102 107 103 void postvisit( const ast::UntypedExpr * ) { … … 110 106 111 107 void postvisit( const ast::ConstantExpr * expr ) { // only handle int constants 112 value = expr->intValue(); 108 result.knownValue = expr->intValue(); 109 result.hasKnownValue = true; 110 result.isEvaluableInGCC = true; 113 111 } 114 112 115 113 void postvisit( const ast::SizeofExpr * ) { 116 // do not change valid or value => let C figure it out117 cfavalid = false;114 result.hasKnownValue = false; 115 result.isEvaluableInGCC = true; 118 116 } 119 117 120 118 void postvisit( const ast::AlignofExpr * ) { 121 // do not change valid or value => let C figure it out122 cfavalid = false;119 result.hasKnownValue = false; 120 result.isEvaluableInGCC = true; 123 121 } 124 122 125 123 void postvisit( const ast::OffsetofExpr * ) { 126 // do not change valid or value => let C figure it out127 cfavalid = false;124 result.hasKnownValue = false; 125 result.isEvaluableInGCC = true; 128 126 } 129 127 130 128 void postvisit( const ast::LogicalExpr * expr ) { 131 std::pair<long long int, bool>arg1, arg2;129 Evaluation arg1, arg2; 132 130 arg1 = eval( expr->arg1 ); 133 valid &= arg1.second;134 if ( ! valid) return;131 result.isEvaluableInGCC &= arg1.isEvaluableInGCC; 132 if ( ! result.isEvaluableInGCC ) return; 135 133 arg2 = eval( expr->arg2 ); 136 valid &= arg2.second; 137 if ( ! valid ) return; 134 result.isEvaluableInGCC &= arg2.isEvaluableInGCC; 135 if ( ! result.isEvaluableInGCC ) return; 136 137 result.hasKnownValue &= arg1.hasKnownValue; 138 result.hasKnownValue &= arg2.hasKnownValue; 139 if ( ! result.hasKnownValue ) return; 138 140 139 141 if ( expr->isAnd ) { 140 value = arg1.first && arg2.first;142 result.knownValue = arg1.knownValue && arg2.knownValue; 141 143 } else { 142 value = arg1.first || arg2.first;144 result.knownValue = arg1.knownValue || arg2.knownValue; 143 145 } // if 144 146 } 145 147 146 148 void postvisit( const ast::ConditionalExpr * expr ) { 147 std::pair<long long int, bool>arg1, arg2, arg3;149 Evaluation arg1, arg2, arg3; 148 150 arg1 = eval( expr->arg1 ); 149 valid &= arg1.second;150 if ( ! valid) return;151 result.isEvaluableInGCC &= arg1.isEvaluableInGCC; 152 if ( ! result.isEvaluableInGCC ) return; 151 153 arg2 = eval( expr->arg2 ); 152 valid &= arg2.second;153 if ( ! valid) return;154 result.isEvaluableInGCC &= arg2.isEvaluableInGCC; 155 if ( ! result.isEvaluableInGCC ) return; 154 156 arg3 = eval( expr->arg3 ); 155 valid &= arg3.second; 156 if ( ! valid ) return; 157 158 value = arg1.first ? arg2.first : arg3.first; 157 result.isEvaluableInGCC &= arg3.isEvaluableInGCC; 158 if ( ! result.isEvaluableInGCC ) return; 159 160 result.hasKnownValue &= arg1.hasKnownValue; 161 result.hasKnownValue &= arg2.hasKnownValue; 162 result.hasKnownValue &= arg3.hasKnownValue; 163 if ( ! result.hasKnownValue ) return; 164 165 result.knownValue = arg1.knownValue ? arg2.knownValue : arg3.knownValue; 159 166 } 160 167 161 168 void postvisit( const ast::CastExpr * expr ) { 162 // cfa-cc generates a cast before every constant and many other places, e.g., (int)3, so the cast argument must 163 // be evaluated to get the constant value. 164 auto arg = eval(expr->arg); 165 valid = arg.second; 166 value = arg.first; 167 cfavalid = false; 169 // cfa-cc generates a cast before every constant and many other places, e.g., (int)3, 170 // so we must use the value from the cast argument, even though we lack any basis for evaluating wraparound effects, etc 171 result = eval(expr->arg); 168 172 } 169 173 170 174 void postvisit( const ast::VariableExpr * expr ) { 175 result.hasKnownValue = false; 176 result.isEvaluableInGCC = false; 171 177 if ( const ast::EnumInstType * inst = dynamic_cast<const ast::EnumInstType *>(expr->result.get()) ) { 172 178 if ( const ast::EnumDecl * decl = inst->base ) { 173 if ( decl->valueOf( expr->var, value ) ) { // value filled by valueOf 174 return; 175 } 179 result.isEvaluableInGCC = true; 180 result.hasKnownValue = decl->valueOf( expr->var, result.knownValue ); // result.knownValue filled by valueOf 176 181 } 177 182 } 178 valid = false;179 183 } 180 184 181 185 void postvisit( const ast::ApplicationExpr * expr ) { 182 186 const ast::DeclWithType * function = ast::getFunction(expr); 183 if ( ! function || function->linkage != ast::Linkage::Intrinsic ) { valid = false; return; } 187 if ( ! function || function->linkage != ast::Linkage::Intrinsic ) { 188 result.isEvaluableInGCC = false; 189 result.hasKnownValue = false; 190 return; 191 } 184 192 const std::string & fname = function->name; 185 193 assertf( expr->args.size() == 1 || expr->args.size() == 2, "Intrinsic function with %zd arguments: %s", expr->args.size(), fname.c_str() ); … … 187 195 if ( expr->args.size() == 1 ) { 188 196 // pre/postfix operators ++ and -- => assignment, which is not constant 189 std::pair<long long int, bool>arg1;197 Evaluation arg1; 190 198 arg1 = eval(expr->args.front()); 191 valid &= arg1.second; 192 if ( ! valid ) return; 199 result.isEvaluableInGCC &= arg1.isEvaluableInGCC; 200 if ( ! result.isEvaluableInGCC ) return; 201 202 result.hasKnownValue &= arg1.hasKnownValue; 203 if ( ! result.hasKnownValue ) return; 193 204 194 205 if (fname == "+?") { 195 value = arg1.first;206 result.knownValue = arg1.knownValue; 196 207 } else if (fname == "-?") { 197 value = -arg1.first;208 result.knownValue = -arg1.knownValue; 198 209 } else if (fname == "~?") { 199 value = ~arg1.first;210 result.knownValue = ~arg1.knownValue; 200 211 } else if (fname == "!?") { 201 value = ! arg1.first;212 result.knownValue = ! arg1.knownValue; 202 213 } else { 203 valid = false; 214 result.isEvaluableInGCC = false; 215 result.hasKnownValue = false; 204 216 } // if 205 217 } else { // => expr->args.size() == 2 206 218 // infix assignment operators => assignment, which is not constant 207 std::pair<long long int, bool>arg1, arg2;219 Evaluation arg1, arg2; 208 220 arg1 = eval(expr->args.front()); 209 valid &= arg1.second;210 if ( ! valid) return;221 result.isEvaluableInGCC &= arg1.isEvaluableInGCC; 222 if ( ! result.isEvaluableInGCC ) return; 211 223 arg2 = eval(expr->args.back()); 212 valid &= arg2.second; 213 if ( ! valid ) return; 224 result.isEvaluableInGCC &= arg2.isEvaluableInGCC; 225 if ( ! result.isEvaluableInGCC ) return; 226 227 result.hasKnownValue &= arg1.hasKnownValue; 228 result.hasKnownValue &= arg2.hasKnownValue; 229 if ( ! result.hasKnownValue ) return; 214 230 215 231 if (fname == "?+?") { 216 value = arg1.first + arg2.first;232 result.knownValue = arg1.knownValue + arg2.knownValue; 217 233 } else if (fname == "?-?") { 218 value = arg1.first - arg2.first;234 result.knownValue = arg1.knownValue - arg2.knownValue; 219 235 } else if (fname == "?*?") { 220 value = arg1.first * arg2.first;236 result.knownValue = arg1.knownValue * arg2.knownValue; 221 237 } else if (fname == "?/?") { 222 if ( arg2. first ) value = arg1.first / arg2.first;238 if ( arg2.knownValue ) result.knownValue = arg1.knownValue / arg2.knownValue; 223 239 } else if (fname == "?%?") { 224 if ( arg2. first ) value = arg1.first % arg2.first;240 if ( arg2.knownValue ) result.knownValue = arg1.knownValue % arg2.knownValue; 225 241 } else if (fname == "?<<?") { 226 value = arg1.first << arg2.first;242 result.knownValue = arg1.knownValue << arg2.knownValue; 227 243 } else if (fname == "?>>?") { 228 value = arg1.first >> arg2.first;244 result.knownValue = arg1.knownValue >> arg2.knownValue; 229 245 } else if (fname == "?<?") { 230 value = arg1.first < arg2.first;246 result.knownValue = arg1.knownValue < arg2.knownValue; 231 247 } else if (fname == "?>?") { 232 value = arg1.first > arg2.first;248 result.knownValue = arg1.knownValue > arg2.knownValue; 233 249 } else if (fname == "?<=?") { 234 value = arg1.first <= arg2.first;250 result.knownValue = arg1.knownValue <= arg2.knownValue; 235 251 } else if (fname == "?>=?") { 236 value = arg1.first >= arg2.first;252 result.knownValue = arg1.knownValue >= arg2.knownValue; 237 253 } else if (fname == "?==?") { 238 value = arg1.first == arg2.first;254 result.knownValue = arg1.knownValue == arg2.knownValue; 239 255 } else if (fname == "?!=?") { 240 value = arg1.first != arg2.first;256 result.knownValue = arg1.knownValue != arg2.knownValue; 241 257 } else if (fname == "?&?") { 242 value = arg1.first & arg2.first;258 result.knownValue = arg1.knownValue & arg2.knownValue; 243 259 } else if (fname == "?^?") { 244 value = arg1.first ^ arg2.first;260 result.knownValue = arg1.knownValue ^ arg2.knownValue; 245 261 } else if (fname == "?|?") { 246 value = arg1.first | arg2.first;262 result.knownValue = arg1.knownValue | arg2.knownValue; 247 263 } else { 248 valid = false; 264 result.isEvaluableInGCC = false; 265 result.hasKnownValue = false; 249 266 } 250 267 } // if … … 263 280 } 264 281 265 std::pair<long long int, bool> eval( const ast::Expr * expr ) { 266 ast::Pass<EvalNew> ev; 282 Evaluation eval( const ast::Expr * expr ) { 267 283 if ( expr ) { 268 expr->accept( ev ); 269 return std::make_pair( ev.core.value, ev.core.valid ); 284 285 return ast::Pass<EvalNew>::read(expr); 286 // Evaluation ret = ast::Pass<EvalNew>::read(expr); 287 // ret.knownValue = 777; 288 // return ret; 289 270 290 } else { 271 return std::make_pair( 0, false );291 return { 0, false, false }; 272 292 } 273 293 } -
src/Common/Eval.h
rfa5e1aa5 rb7b3e41 23 23 } 24 24 25 struct Evaluation { 26 long long int knownValue; 27 bool hasKnownValue; 28 bool isEvaluableInGCC; 29 }; 30 25 31 /// Evaluates expr as a long long int. 26 32 /// If second is false, expr could not be evaluated. 27 33 std::pair<long long int, bool> eval(const Expression * expr); 28 std::pair<long long int, bool>eval(const ast::Expr * expr);34 Evaluation eval(const ast::Expr * expr); 29 35 30 36 // Local Variables: // -
src/Concurrency/Actors.cpp
rfa5e1aa5 rb7b3e41 38 38 bool namedDecl = false; 39 39 40 // finds and sets a ptr to the Allocation enum, which is needed in the next pass40 // finds and sets a ptr to the allocation enum, which is needed in the next pass 41 41 void previsit( const EnumDecl * decl ) { 42 if( decl->name == " Allocation" ) *allocationDecl = decl;42 if( decl->name == "allocation" ) *allocationDecl = decl; 43 43 } 44 44 … … 227 227 static inline derived_actor & ?|?( derived_actor & receiver, derived_msg & msg ) { 228 228 request new_req; 229 Allocation (*my_work_fn)( derived_actor &, derived_msg & ) = receive;229 allocation (*my_work_fn)( derived_actor &, derived_msg & ) = receive; 230 230 __receive_fn fn = (__receive_fn)my_work_fn; 231 231 new_req{ &receiver, &msg, fn }; … … 246 246 )); 247 247 248 // Function type is: Allocation (*)( derived_actor &, derived_msg & )248 // Function type is: allocation (*)( derived_actor &, derived_msg & ) 249 249 FunctionType * derivedReceive = new FunctionType(); 250 250 derivedReceive->params.push_back( ast::deepCopy( derivedActorRef ) ); … … 252 252 derivedReceive->returns.push_back( new EnumInstType( *allocationDecl ) ); 253 253 254 // Generates: Allocation (*my_work_fn)( derived_actor &, derived_msg & ) = receive;254 // Generates: allocation (*my_work_fn)( derived_actor &, derived_msg & ) = receive; 255 255 sendBody->push_back( new DeclStmt( 256 256 decl->location, … … 263 263 )); 264 264 265 // Function type is: Allocation (*)( actor &, message & )265 // Function type is: allocation (*)( actor &, message & ) 266 266 FunctionType * genericReceive = new FunctionType(); 267 267 genericReceive->params.push_back( new ReferenceType( new StructInstType( *actorDecl ) ) ); … … 269 269 genericReceive->returns.push_back( new EnumInstType( *allocationDecl ) ); 270 270 271 // Generates: Allocation (*fn)( actor &, message & ) = (Allocation (*)( actor &, message & ))my_work_fn;271 // Generates: allocation (*fn)( actor &, message & ) = (allocation (*)( actor &, message & ))my_work_fn; 272 272 // More readable synonymous code: 273 // typedef Allocation (*__receive_fn)(actor &, message &);273 // typedef allocation (*__receive_fn)(actor &, message &); 274 274 // __receive_fn fn = (__receive_fn)my_work_fn; 275 275 sendBody->push_back( new DeclStmt( … … 285 285 )); 286 286 287 // Generates: new_req{ &receiver, &msg, fn };287 // Generates: new_req{ &receiver, (actor *)&receiver, &msg, (message *)&msg, fn }; 288 288 sendBody->push_back( new ExprStmt( 289 289 decl->location, … … 294 294 new NameExpr( decl->location, "new_req" ), 295 295 new AddressExpr( new NameExpr( decl->location, "receiver" ) ), 296 new CastExpr( decl->location, new AddressExpr( new NameExpr( decl->location, "receiver" ) ), new PointerType( new StructInstType( *actorDecl ) ), ExplicitCast ), 296 297 new AddressExpr( new NameExpr( decl->location, "msg" ) ), 298 new CastExpr( decl->location, new AddressExpr( new NameExpr( decl->location, "msg" ) ), new PointerType( new StructInstType( *msgDecl ) ), ExplicitCast ), 297 299 new NameExpr( decl->location, "fn" ) 298 300 } … … 321 323 FunctionDecl * sendOperatorFunction = new FunctionDecl( 322 324 decl->location, 323 "? <<?",325 "?|?", 324 326 {}, // forall 325 327 { … … 422 424 const StructDecl ** msgDecl = &msgDeclPtr; 423 425 424 // first pass collects ptrs to Allocation enum, request type, and generic receive fn typedef426 // first pass collects ptrs to allocation enum, request type, and generic receive fn typedef 425 427 // also populates maps of all derived actors and messages 426 428 Pass<CollectactorStructDecls>::run( translationUnit, actorStructDecls, messageStructDecls, requestDecl, -
src/GenPoly/SpecializeNew.cpp
rfa5e1aa5 rb7b3e41 113 113 using namespace ResolvExpr; 114 114 ast::OpenVarSet openVars, closedVars; 115 ast::AssertionSet need, have; 116 findOpenVars( formalType, openVars, closedVars, need, have, FirstClosed ); 117 findOpenVars( actualType, openVars, closedVars, need, have, FirstOpen ); 115 ast::AssertionSet need, have; // unused 116 ast::TypeEnvironment env; // unused 117 // findOpenVars( formalType, openVars, closedVars, need, have, FirstClosed ); 118 findOpenVars( actualType, openVars, closedVars, need, have, env, FirstOpen ); 118 119 for ( const ast::OpenVarSet::value_type & openVar : openVars ) { 119 120 const ast::Type * boundType = subs->lookup( openVar.first ); … … 125 126 if ( closedVars.find( *inst ) == closedVars.end() ) { 126 127 return true; 128 } 129 else { 130 assertf(false, "closed: %s", inst->name.c_str()); 127 131 } 128 132 // Otherwise, the variable is bound to a concrete type. -
src/Parser/DeclarationNode.cc
rfa5e1aa5 rb7b3e41 9 9 // Author : Rodolfo G. Esteves 10 10 // Created On : Sat May 16 12:34:05 2015 11 // Last Modified By : Andrew Beach12 // Last Modified On : Thr Apr 20 11:46:00202313 // Update Count : 1 39311 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sat Jun 17 14:41:48 2023 13 // Update Count : 1405 14 14 // 15 15 … … 459 459 std::vector<ast::ptr<ast::Expr>> exprs; 460 460 buildList( expr, exprs ); 461 newnode->attributes.push_back( 462 new ast::Attribute( *name, std::move( exprs ) ) ); 461 newnode->attributes.push_back( new ast::Attribute( *name, std::move( exprs ) ) ); 463 462 delete name; 464 463 return newnode; … … 633 632 dst->basictype = src->basictype; 634 633 } else if ( src->basictype != DeclarationNode::NoBasicType ) 635 SemanticError( yylloc, src, string( "conflicting type specifier " ) + DeclarationNode::basicTypeNames[ src->basictype ] + " in type: " ); 634 SemanticError( yylloc, string( "multiple declaration types \"" ) + DeclarationNode::basicTypeNames[ dst->basictype ] + 635 "\" and \"" + DeclarationNode::basicTypeNames[ src->basictype ] + "\"." ); 636 636 637 637 if ( dst->complextype == DeclarationNode::NoComplexType ) { 638 638 dst->complextype = src->complextype; 639 639 } else if ( src->complextype != DeclarationNode::NoComplexType ) 640 SemanticError( yylloc, src, string( "conflicting type specifier " ) + DeclarationNode::complexTypeNames[ src->complextype ] + " in type: " ); 640 SemanticError( yylloc, string( "multiple declaration types \"" ) + DeclarationNode::complexTypeNames[ src->complextype ] + 641 "\" and \"" + DeclarationNode::complexTypeNames[ src->complextype ] + "\"." ); 641 642 642 643 if ( dst->signedness == DeclarationNode::NoSignedness ) { 643 644 dst->signedness = src->signedness; 644 645 } else if ( src->signedness != DeclarationNode::NoSignedness ) 645 SemanticError( yylloc, src, string( "conflicting type specifier " ) + DeclarationNode::signednessNames[ src->signedness ] + " in type: " ); 646 SemanticError( yylloc, string( "conflicting type specifier \"" ) + DeclarationNode::signednessNames[ dst->signedness ] + 647 "\" and \"" + DeclarationNode::signednessNames[ src->signedness ] + "\"." ); 646 648 647 649 if ( dst->length == DeclarationNode::NoLength ) { … … 650 652 dst->length = DeclarationNode::LongLong; 651 653 } else if ( src->length != DeclarationNode::NoLength ) 652 SemanticError( yylloc, src, string( "conflicting type specifier " ) + DeclarationNode::lengthNames[ src->length ] + " in type: " ); 654 SemanticError( yylloc, string( "conflicting type specifier \"" ) + DeclarationNode::lengthNames[ dst->length ] + 655 "\" and \"" + DeclarationNode::lengthNames[ src->length ] + "\"." ); 653 656 } // if 654 657 break; … … 718 721 719 722 DeclarationNode * DeclarationNode::addEnumBase( DeclarationNode * o ) { 720 if ( o && o ->type) {723 if ( o && o->type) { 721 724 type->base= o->type; 722 } 725 } // if 723 726 delete o; 724 727 return this; … … 1003 1006 } 1004 1007 1005 // If a typedef wraps an anonymous declaration, name the inner declaration 1006 // so it has a consistent name acrosstranslation units.1008 // If a typedef wraps an anonymous declaration, name the inner declaration so it has a consistent name across 1009 // translation units. 1007 1010 static void nameTypedefedDecl( 1008 1011 DeclarationNode * innerDecl, … … 1085 1088 } 1086 1089 1087 void buildList( DeclarationNode * firstNode, 1088 std::vector<ast::ptr<ast::Decl>> & outputList ) { 1090 void buildList( DeclarationNode * firstNode, std::vector<ast::ptr<ast::Decl>> & outputList ) { 1089 1091 SemanticErrorException errors; 1090 1092 std::back_insert_iterator<std::vector<ast::ptr<ast::Decl>>> out( outputList ); -
src/Parser/ExpressionNode.cc
rfa5e1aa5 rb7b3e41 601 601 ast::Expr * build_cast( const CodeLocation & location, 602 602 DeclarationNode * decl_node, 603 ExpressionNode * expr_node ) { 603 ExpressionNode * expr_node, 604 ast::CastExpr::CastKind kind ) { 604 605 ast::Type * targetType = maybeMoveBuildType( decl_node ); 605 606 if ( dynamic_cast<ast::VoidType *>( targetType ) ) { … … 607 608 return new ast::CastExpr( location, 608 609 maybeMoveBuild( expr_node ), 609 ast::ExplicitCast );610 ast::ExplicitCast, kind ); 610 611 } else { 611 612 return new ast::CastExpr( location, 612 613 maybeMoveBuild( expr_node ), 613 614 targetType, 614 ast::ExplicitCast );615 ast::ExplicitCast, kind ); 615 616 } // if 616 617 } // build_cast -
src/Parser/ExpressionNode.h
rfa5e1aa5 rb7b3e41 69 69 ast::DimensionExpr * build_dimensionref( const CodeLocation &, const std::string * name ); 70 70 71 ast::Expr * build_cast( const CodeLocation &, DeclarationNode * decl_node, ExpressionNode * expr_node );71 ast::Expr * build_cast( const CodeLocation &, DeclarationNode * decl_node, ExpressionNode * expr_node, ast::CastExpr::CastKind kind = ast::CastExpr::Default ); 72 72 ast::Expr * build_keyword_cast( const CodeLocation &, ast::AggregateDecl::Aggregate target, ExpressionNode * expr_node ); 73 73 ast::Expr * build_virtual_cast( const CodeLocation &, DeclarationNode * decl_node, ExpressionNode * expr_node ); -
src/Parser/lex.ll
rfa5e1aa5 rb7b3e41 10 10 * Created On : Sat Sep 22 08:58:10 2001 11 11 * Last Modified By : Peter A. Buhr 12 * Last Modified On : Tue May 2 08:45:21202313 * Update Count : 7 6912 * Last Modified On : Fri Jun 9 10:04:00 2023 13 * Update Count : 770 14 14 */ 15 15 … … 319 319 static { KEYWORD_RETURN(STATIC); } 320 320 _Static_assert { KEYWORD_RETURN(STATICASSERT); } // C11 321 _static_assert { KEYWORD_RETURN(STATICASSERT); } // C23 321 322 struct { KEYWORD_RETURN(STRUCT); } 322 323 suspend { KEYWORD_RETURN(SUSPEND); } // CFA -
src/Parser/parser.yy
rfa5e1aa5 rb7b3e41 10 10 // Created On : Sat Sep 1 20:22:55 2001 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Wed Apr 26 16:45:37202313 // Update Count : 63 3012 // Last Modified On : Sat Jun 17 18:53:24 2023 13 // Update Count : 6347 14 14 // 15 15 … … 108 108 assert( declList ); 109 109 // printf( "distAttr1 typeSpec %p\n", typeSpec ); typeSpec->print( std::cout ); 110 DeclarationNode * c ur = declList, * cl = (new DeclarationNode)->addType( typeSpec );110 DeclarationNode * cl = (new DeclarationNode)->addType( typeSpec ); 111 111 // printf( "distAttr2 cl %p\n", cl ); cl->type->print( std::cout ); 112 112 // cl->type->aggregate.name = cl->type->aggInst.aggregate->aggregate.name; 113 113 114 for ( cur = dynamic_cast<DeclarationNode *>( cur->get_next() ); cur != nullptr; cur = dynamic_cast<DeclarationNode *>( cur->get_next() ) ) {114 for ( DeclarationNode * cur = dynamic_cast<DeclarationNode *>( declList->get_next() ); cur != nullptr; cur = dynamic_cast<DeclarationNode *>( cur->get_next() ) ) { 115 115 cl->cloneBaseType( cur ); 116 116 } // for … … 206 206 #define NEW_ONE new ExpressionNode( build_constantInteger( yylloc, *new string( "1" ) ) ) 207 207 #define UPDOWN( compop, left, right ) (compop == OperKinds::LThan || compop == OperKinds::LEThan ? left : right) 208 #define MISSING_ANON_FIELD " Missing loop fields with an anonymous loop index is meaningless as loop index is unavailable in loop body."209 #define MISSING_LOW " Missing low value for up-to range so index is uninitialized."210 #define MISSING_HIGH " Missing high value for down-to range so index is uninitialized."208 #define MISSING_ANON_FIELD "syntax error, missing loop fields with an anonymous loop index is meaningless as loop index is unavailable in loop body." 209 #define MISSING_LOW "syntax error, missing low value for up-to range so index is uninitialized." 210 #define MISSING_HIGH "syntax error, missing high value for down-to range so index is uninitialized." 211 211 212 212 static ForCtrl * makeForCtrl( … … 232 232 ForCtrl * forCtrl( const CodeLocation & location, DeclarationNode * index, ExpressionNode * start, enum OperKinds compop, ExpressionNode * comp, ExpressionNode * inc ) { 233 233 if ( index->initializer ) { 234 SemanticError( yylloc, " Direct initialization disallowed. Use instead: type var; initialization ~ comparison ~ increment." );234 SemanticError( yylloc, "syntax error, direct initialization disallowed. Use instead: type var; initialization ~ comparison ~ increment." ); 235 235 } // if 236 236 if ( index->next ) { 237 SemanticError( yylloc, " Multiple loop indexes disallowed in for-loop declaration." );237 SemanticError( yylloc, "syntax error, multiple loop indexes disallowed in for-loop declaration." ); 238 238 } // if 239 239 DeclarationNode * initDecl = index->addInitializer( new InitializerNode( start ) ); … … 260 260 return forCtrl( location, type, new string( identifier->name ), start, compop, comp, inc ); 261 261 } else { 262 SemanticError( yylloc, " Expression disallowed. Only loop-index nameallowed." ); return nullptr;262 SemanticError( yylloc, "syntax error, loop-index name missing. Expression disallowed." ); return nullptr; 263 263 } // if 264 264 } else { 265 SemanticError( yylloc, " Expression disallowed. Only loop-index name allowed." ); return nullptr;265 SemanticError( yylloc, "syntax error, loop-index name missing. Expression disallowed. ." ); return nullptr; 266 266 } // if 267 267 } // forCtrl 268 268 269 269 static void IdentifierBeforeIdentifier( string & identifier1, string & identifier2, const char * kind ) { 270 SemanticError( yylloc, ::toString( " Adjacent identifiers \"", identifier1, "\" and \"", identifier2, "\" are not meaningful in a", kind, ".\n"270 SemanticError( yylloc, ::toString( "syntax error, adjacent identifiers \"", identifier1, "\" and \"", identifier2, "\" are not meaningful in a", kind, ".\n" 271 271 "Possible cause is misspelled type name or missing generic parameter." ) ); 272 272 } // IdentifierBeforeIdentifier 273 273 274 274 static void IdentifierBeforeType( string & identifier, const char * kind ) { 275 SemanticError( yylloc, ::toString( " Identifier \"", identifier, "\" cannot appear before a ", kind, ".\n"275 SemanticError( yylloc, ::toString( "syntax error, identifier \"", identifier, "\" cannot appear before a ", kind, ".\n" 276 276 "Possible cause is misspelled storage/CV qualifier, misspelled typename, or missing generic parameter." ) ); 277 277 } // IdentifierBeforeType … … 689 689 // | RESUME '(' comma_expression ')' compound_statement 690 690 // { SemanticError( yylloc, "Resume expression is currently unimplemented." ); $$ = nullptr; } 691 | IDENTIFIER IDENTIFIER // syntax error691 | IDENTIFIER IDENTIFIER // invalid syntax rules 692 692 { IdentifierBeforeIdentifier( *$1.str, *$2.str, "n expression" ); $$ = nullptr; } 693 | IDENTIFIER type_qualifier // syntax error693 | IDENTIFIER type_qualifier // invalid syntax rules 694 694 { IdentifierBeforeType( *$1.str, "type qualifier" ); $$ = nullptr; } 695 | IDENTIFIER storage_class // syntax error695 | IDENTIFIER storage_class // invalid syntax rules 696 696 { IdentifierBeforeType( *$1.str, "storage class" ); $$ = nullptr; } 697 | IDENTIFIER basic_type_name // syntax error697 | IDENTIFIER basic_type_name // invalid syntax rules 698 698 { IdentifierBeforeType( *$1.str, "type" ); $$ = nullptr; } 699 | IDENTIFIER TYPEDEFname // syntax error699 | IDENTIFIER TYPEDEFname // invalid syntax rules 700 700 { IdentifierBeforeType( *$1.str, "type" ); $$ = nullptr; } 701 | IDENTIFIER TYPEGENname // syntax error701 | IDENTIFIER TYPEGENname // invalid syntax rules 702 702 { IdentifierBeforeType( *$1.str, "type" ); $$ = nullptr; } 703 703 ; … … 931 931 { $$ = new ExpressionNode( new ast::VirtualCastExpr( yylloc, maybeMoveBuild( $5 ), maybeMoveBuildType( $3 ) ) ); } 932 932 | '(' RETURN type_no_function ')' cast_expression // CFA 933 { SemanticError( yylloc, "Return cast is currently unimplemented." ); $$ = nullptr; }933 { $$ = new ExpressionNode( build_cast( yylloc, $3, $5, ast::CastExpr::Return ) ); } 934 934 | '(' COERCE type_no_function ')' cast_expression // CFA 935 935 { SemanticError( yylloc, "Coerce cast is currently unimplemented." ); $$ = nullptr; } … … 1040 1040 // FIX ME: computes $1 twice 1041 1041 | logical_OR_expression '?' /* empty */ ':' conditional_expression // GCC, omitted first operand 1042 { $$ = new ExpressionNode( build_cond( yylloc, $1, $1 , $4 ) ); }1042 { $$ = new ExpressionNode( build_cond( yylloc, $1, $1->clone(), $4 ) ); } 1043 1043 ; 1044 1044 … … 1152 1152 identifier_or_type_name ':' attribute_list_opt statement 1153 1153 { $$ = $4->add_label( yylloc, $1, $3 ); } 1154 | identifier_or_type_name ':' attribute_list_opt error // syntax error1155 { 1156 SemanticError( yylloc, ::toString( " Label \"", *$1.str, "\" must be associated with a statement, "1154 | identifier_or_type_name ':' attribute_list_opt error // invalid syntax rule 1155 { 1156 SemanticError( yylloc, ::toString( "syntx error, label \"", *$1.str, "\" must be associated with a statement, " 1157 1157 "where a declaration, case, or default is not a statement. " 1158 1158 "Move the label or terminate with a semi-colon." ) ); … … 1193 1193 | statement_list_nodecl statement 1194 1194 { assert( $1 ); $1->set_last( $2 ); $$ = $1; } 1195 | statement_list_nodecl error // syntax error1196 { SemanticError( yylloc, " Declarations only allowed at the start of the switch body, i.e., after the '{'." ); $$ = nullptr; }1195 | statement_list_nodecl error // invalid syntax rule 1196 { SemanticError( yylloc, "syntax error, declarations only allowed at the start of the switch body, i.e., after the '{'." ); $$ = nullptr; } 1197 1197 ; 1198 1198 … … 1219 1219 $$ = $7 ? new StatementNode( build_compound( yylloc, (StatementNode *)((new StatementNode( $7 ))->set_last( sw )) ) ) : sw; 1220 1220 } 1221 | SWITCH '(' comma_expression ')' '{' error '}' // CFA, syntaxerror1222 { SemanticError( yylloc, " Only declarations canappear before the list of case clauses." ); $$ = nullptr; }1221 | SWITCH '(' comma_expression ')' '{' error '}' // CFA, invalid syntax rule error 1222 { SemanticError( yylloc, "synatx error, declarations can only appear before the list of case clauses." ); $$ = nullptr; } 1223 1223 | CHOOSE '(' comma_expression ')' case_clause // CFA 1224 1224 { $$ = new StatementNode( build_switch( yylloc, false, $3, $5 ) ); } … … 1228 1228 $$ = $7 ? new StatementNode( build_compound( yylloc, (StatementNode *)((new StatementNode( $7 ))->set_last( sw )) ) ) : sw; 1229 1229 } 1230 | CHOOSE '(' comma_expression ')' '{' error '}' // CFA, syntax error1231 { SemanticError( yylloc, " Only declarations canappear before the list of case clauses." ); $$ = nullptr; }1230 | CHOOSE '(' comma_expression ')' '{' error '}' // CFA, invalid syntax rule 1231 { SemanticError( yylloc, "syntax error, declarations can only appear before the list of case clauses." ); $$ = nullptr; } 1232 1232 ; 1233 1233 … … 1268 1268 1269 1269 case_label: // CFA 1270 CASE error // syntax error1271 { SemanticError( yylloc, " Missing case listafter case." ); $$ = nullptr; }1270 CASE error // invalid syntax rule 1271 { SemanticError( yylloc, "syntax error, case list missing after case." ); $$ = nullptr; } 1272 1272 | CASE case_value_list ':' { $$ = $2; } 1273 | CASE case_value_list error // syntax error1274 { SemanticError( yylloc, " Missing colonafter case list." ); $$ = nullptr; }1273 | CASE case_value_list error // invalid syntax rule 1274 { SemanticError( yylloc, "syntax error, colon missing after case list." ); $$ = nullptr; } 1275 1275 | DEFAULT ':' { $$ = new ClauseNode( build_default( yylloc ) ); } 1276 1276 // A semantic check is required to ensure only one default clause per switch/choose statement. 1277 | DEFAULT error // syntax error1278 { SemanticError( yylloc, " Missing colonafter default." ); $$ = nullptr; }1277 | DEFAULT error // invalid syntax rules 1278 { SemanticError( yylloc, "syntax error, colon missing after default." ); $$ = nullptr; } 1279 1279 ; 1280 1280 … … 1405 1405 else { SemanticError( yylloc, MISSING_HIGH ); $$ = nullptr; } 1406 1406 } 1407 | comma_expression updowneq comma_expression '~' '@' // CFA, error1407 | comma_expression updowneq comma_expression '~' '@' // CFA, invalid syntax rules 1408 1408 { SemanticError( yylloc, MISSING_ANON_FIELD ); $$ = nullptr; } 1409 | '@' updowneq '@' // CFA, error1409 | '@' updowneq '@' // CFA, invalid syntax rules 1410 1410 { SemanticError( yylloc, MISSING_ANON_FIELD ); $$ = nullptr; } 1411 | '@' updowneq comma_expression '~' '@' // CFA, error1411 | '@' updowneq comma_expression '~' '@' // CFA, invalid syntax rules 1412 1412 { SemanticError( yylloc, MISSING_ANON_FIELD ); $$ = nullptr; } 1413 | comma_expression updowneq '@' '~' '@' // CFA, error1413 | comma_expression updowneq '@' '~' '@' // CFA, invalid syntax rules 1414 1414 { SemanticError( yylloc, MISSING_ANON_FIELD ); $$ = nullptr; } 1415 | '@' updowneq '@' '~' '@' // CFA, error1415 | '@' updowneq '@' '~' '@' // CFA, invalid syntax rules 1416 1416 { SemanticError( yylloc, MISSING_ANON_FIELD ); $$ = nullptr; } 1417 1417 … … 1431 1431 { 1432 1432 if ( $4 == OperKinds::GThan || $4 == OperKinds::GEThan ) { SemanticError( yylloc, MISSING_HIGH ); $$ = nullptr; } 1433 else if ( $4 == OperKinds::LEThan ) { SemanticError( yylloc, " Equality with missing high value is meaningless. Use \"~\"." ); $$ = nullptr; }1433 else if ( $4 == OperKinds::LEThan ) { SemanticError( yylloc, "syntax error, equality with missing high value is meaningless. Use \"~\"." ); $$ = nullptr; } 1434 1434 else $$ = forCtrl( yylloc, $3, $1, $3->clone(), $4, nullptr, NEW_ONE ); 1435 1435 } 1436 | comma_expression ';' '@' updowneq '@' // CFA, error1437 { SemanticError( yylloc, " Missing low/high value for up/down-to range so index is uninitialized." ); $$ = nullptr; }1436 | comma_expression ';' '@' updowneq '@' // CFA, invalid syntax rules 1437 { SemanticError( yylloc, "syntax error, missing low/high value for up/down-to range so index is uninitialized." ); $$ = nullptr; } 1438 1438 1439 1439 | comma_expression ';' comma_expression updowneq comma_expression '~' comma_expression // CFA 1440 1440 { $$ = forCtrl( yylloc, $3, $1, UPDOWN( $4, $3->clone(), $5 ), $4, UPDOWN( $4, $5->clone(), $3->clone() ), $7 ); } 1441 | comma_expression ';' '@' updowneq comma_expression '~' comma_expression // CFA, error1441 | comma_expression ';' '@' updowneq comma_expression '~' comma_expression // CFA, invalid syntax rules 1442 1442 { 1443 1443 if ( $4 == OperKinds::LThan || $4 == OperKinds::LEThan ) { SemanticError( yylloc, MISSING_LOW ); $$ = nullptr; } … … 1447 1447 { 1448 1448 if ( $4 == OperKinds::GThan || $4 == OperKinds::GEThan ) { SemanticError( yylloc, MISSING_HIGH ); $$ = nullptr; } 1449 else if ( $4 == OperKinds::LEThan ) { SemanticError( yylloc, " Equality with missing high value is meaningless. Use \"~\"." ); $$ = nullptr; }1449 else if ( $4 == OperKinds::LEThan ) { SemanticError( yylloc, "syntax error, equality with missing high value is meaningless. Use \"~\"." ); $$ = nullptr; } 1450 1450 else $$ = forCtrl( yylloc, $3, $1, $3->clone(), $4, nullptr, $7 ); 1451 1451 } 1452 1452 | comma_expression ';' comma_expression updowneq comma_expression '~' '@' // CFA 1453 1453 { $$ = forCtrl( yylloc, $3, $1, UPDOWN( $4, $3->clone(), $5 ), $4, UPDOWN( $4, $5->clone(), $3->clone() ), nullptr ); } 1454 | comma_expression ';' '@' updowneq comma_expression '~' '@' // CFA, error1454 | comma_expression ';' '@' updowneq comma_expression '~' '@' // CFA, invalid syntax rules 1455 1455 { 1456 1456 if ( $4 == OperKinds::LThan || $4 == OperKinds::LEThan ) { SemanticError( yylloc, MISSING_LOW ); $$ = nullptr; } … … 1460 1460 { 1461 1461 if ( $4 == OperKinds::GThan || $4 == OperKinds::GEThan ) { SemanticError( yylloc, MISSING_HIGH ); $$ = nullptr; } 1462 else if ( $4 == OperKinds::LEThan ) { SemanticError( yylloc, " Equality with missing high value is meaningless. Use \"~\"." ); $$ = nullptr; }1462 else if ( $4 == OperKinds::LEThan ) { SemanticError( yylloc, "syntax error, equality with missing high value is meaningless. Use \"~\"." ); $$ = nullptr; } 1463 1463 else $$ = forCtrl( yylloc, $3, $1, $3->clone(), $4, nullptr, nullptr ); 1464 1464 } 1465 1465 | comma_expression ';' '@' updowneq '@' '~' '@' // CFA 1466 { SemanticError( yylloc, " Missing low/high value for up/down-to range so index is uninitialized." ); $$ = nullptr; }1466 { SemanticError( yylloc, "syntax error, missing low/high value for up/down-to range so index is uninitialized." ); $$ = nullptr; } 1467 1467 1468 1468 | declaration comma_expression // CFA … … 1481 1481 { 1482 1482 if ( $3 == OperKinds::GThan || $3 == OperKinds::GEThan ) { SemanticError( yylloc, MISSING_HIGH ); $$ = nullptr; } 1483 else if ( $3 == OperKinds::LEThan ) { SemanticError( yylloc, " Equality with missing high value is meaningless. Use \"~\"." ); $$ = nullptr; }1483 else if ( $3 == OperKinds::LEThan ) { SemanticError( yylloc, "syntax error, equality with missing high value is meaningless. Use \"~\"." ); $$ = nullptr; } 1484 1484 else $$ = forCtrl( yylloc, $1, $2, $3, nullptr, NEW_ONE ); 1485 1485 } … … 1495 1495 { 1496 1496 if ( $3 == OperKinds::GThan || $3 == OperKinds::GEThan ) { SemanticError( yylloc, MISSING_HIGH ); $$ = nullptr; } 1497 else if ( $3 == OperKinds::LEThan ) { SemanticError( yylloc, " Equality with missing high value is meaningless. Use \"~\"." ); $$ = nullptr; }1497 else if ( $3 == OperKinds::LEThan ) { SemanticError( yylloc, "syntax error, equality with missing high value is meaningless. Use \"~\"." ); $$ = nullptr; } 1498 1498 else $$ = forCtrl( yylloc, $1, $2, $3, nullptr, $6 ); 1499 1499 } … … 1508 1508 { 1509 1509 if ( $3 == OperKinds::GThan || $3 == OperKinds::GEThan ) { SemanticError( yylloc, MISSING_HIGH ); $$ = nullptr; } 1510 else if ( $3 == OperKinds::LEThan ) { SemanticError( yylloc, " Equality with missing high value is meaningless. Use \"~\"." ); $$ = nullptr; }1510 else if ( $3 == OperKinds::LEThan ) { SemanticError( yylloc, "syntax error, equality with missing high value is meaningless. Use \"~\"." ); $$ = nullptr; } 1511 1511 else $$ = forCtrl( yylloc, $1, $2, $3, nullptr, nullptr ); 1512 1512 } 1513 | declaration '@' updowneq '@' '~' '@' // CFA, error1514 { SemanticError( yylloc, " Missing low/high value for up/down-to range so index is uninitialized." ); $$ = nullptr; }1513 | declaration '@' updowneq '@' '~' '@' // CFA, invalid syntax rules 1514 { SemanticError( yylloc, "syntax error, missing low/high value for up/down-to range so index is uninitialized." ); $$ = nullptr; } 1515 1515 1516 1516 | comma_expression ';' TYPEDEFname // CFA, array type … … 1521 1521 | comma_expression ';' downupdowneq TYPEDEFname // CFA, array type 1522 1522 { 1523 if ( $3 == OperKinds::LEThan || $3 == OperKinds::GEThan ) { SemanticError( yylloc, "All enumation ranges are equal (all values). Remove \"=~\"." ); $$ = nullptr; } 1523 if ( $3 == OperKinds::LEThan || $3 == OperKinds::GEThan ) { 1524 SemanticError( yylloc, "syntax error, all enumeration ranges are equal (all values). Remove \"=~\"." ); $$ = nullptr; 1525 } 1524 1526 SemanticError( yylloc, "Type iterator is currently unimplemented." ); $$ = nullptr; 1525 1527 } … … 1616 1618 MUTEX '(' argument_expression_list_opt ')' statement 1617 1619 { 1618 if ( ! $3 ) { SemanticError( yylloc, " mutex argument list cannot be empty." ); $$ = nullptr; }1620 if ( ! $3 ) { SemanticError( yylloc, "syntax error, mutex argument list cannot be empty." ); $$ = nullptr; } 1619 1621 $$ = new StatementNode( build_mutex( yylloc, $3, $5 ) ); 1620 1622 } … … 1664 1666 { $$ = build_waitfor_timeout( yylloc, $1, $3, $4, maybe_build_compound( yylloc, $5 ) ); } 1665 1667 // "else" must be conditional after timeout or timeout is never triggered (i.e., it is meaningless) 1666 | wor_waitfor_clause wor when_clause_opt timeout statement wor ELSE statement // syntax error1667 { SemanticError( yylloc, " else clause must be conditional after timeout or timeout never triggered." ); $$ = nullptr; }1668 | wor_waitfor_clause wor when_clause_opt timeout statement wor ELSE statement // invalid syntax rules 1669 { SemanticError( yylloc, "syntax error, else clause must be conditional after timeout or timeout never triggered." ); $$ = nullptr; } 1668 1670 | wor_waitfor_clause wor when_clause_opt timeout statement wor when_clause ELSE statement 1669 1671 { $$ = build_waitfor_else( yylloc, build_waitfor_timeout( yylloc, $1, $3, $4, maybe_build_compound( yylloc, $5 ) ), $7, maybe_build_compound( yylloc, $9 ) ); } … … 1709 1711 { $$ = new ast::WaitUntilStmt::ClauseNode( ast::WaitUntilStmt::ClauseNode::Op::LEFT_OR, $1, build_waituntil_timeout( yylloc, $3, $4, maybe_build_compound( yylloc, $5 ) ) ); } 1710 1712 // "else" must be conditional after timeout or timeout is never triggered (i.e., it is meaningless) 1711 | wor_waituntil_clause wor when_clause_opt timeout statement wor ELSE statement // syntax error1712 { SemanticError( yylloc, " else clause must be conditional after timeout or timeout never triggered." ); $$ = nullptr; }1713 | wor_waituntil_clause wor when_clause_opt timeout statement wor ELSE statement // invalid syntax rules 1714 { SemanticError( yylloc, "syntax error, else clause must be conditional after timeout or timeout never triggered." ); $$ = nullptr; } 1713 1715 | wor_waituntil_clause wor when_clause_opt timeout statement wor when_clause ELSE statement 1714 1716 { $$ = new ast::WaitUntilStmt::ClauseNode( ast::WaitUntilStmt::ClauseNode::Op::LEFT_OR, $1, … … 2065 2067 assert( $1->type ); 2066 2068 if ( $1->type->qualifiers.any() ) { // CV qualifiers ? 2067 SemanticError( yylloc, " Useless type qualifier(s) in empty declaration." ); $$ = nullptr;2069 SemanticError( yylloc, "syntax error, useless type qualifier(s) in empty declaration." ); $$ = nullptr; 2068 2070 } 2069 2071 // enums are never empty declarations because there must have at least one enumeration. 2070 2072 if ( $1->type->kind == TypeData::AggregateInst && $1->storageClasses.any() ) { // storage class ? 2071 SemanticError( yylloc, " Useless storage qualifier(s) in empty aggregate declaration." ); $$ = nullptr;2073 SemanticError( yylloc, "syntax error, useless storage qualifier(s) in empty aggregate declaration." ); $$ = nullptr; 2072 2074 } 2073 2075 } … … 2100 2102 | type_declaration_specifier 2101 2103 | sue_declaration_specifier 2102 | sue_declaration_specifier invalid_types 2103 { 2104 SemanticError( yylloc, ::toString( " Missing ';' afterend of ",2104 | sue_declaration_specifier invalid_types // invalid syntax rule 2105 { 2106 SemanticError( yylloc, ::toString( "syntax error, expecting ';' at end of ", 2105 2107 $1->type->enumeration.name ? "enum" : ast::AggregateDecl::aggrString( $1->type->aggregate.kind ), 2106 " declaration " ) );2108 " declaration." ) ); 2107 2109 $$ = nullptr; 2108 2110 } … … 2584 2586 // } // for 2585 2587 } 2588 | type_specifier field_declaring_list_opt '}' // invalid syntax rule 2589 { 2590 SemanticError( yylloc, ::toString( "syntax error, expecting ';' at end of previous declaration." ) ); 2591 $$ = nullptr; 2592 } 2586 2593 | EXTENSION type_specifier field_declaring_list_opt ';' // GCC 2587 2594 { $$ = fieldDecl( $2, $3 ); distExt( $$ ); } … … 2682 2689 | ENUM '(' cfa_abstract_parameter_declaration ')' attribute_list_opt '{' enumerator_list comma_opt '}' 2683 2690 { 2684 if ( $3->storageClasses.val != 0 || $3->type->qualifiers.any() ) 2685 { SemanticError( yylloc, "storage-class and CV qualifiers are not meaningful for enumeration constants, which are const." ); }2686 2691 if ( $3->storageClasses.val != 0 || $3->type->qualifiers.any() ) { 2692 SemanticError( yylloc, "syntax error, storage-class and CV qualifiers are not meaningful for enumeration constants, which are const." ); 2693 } 2687 2694 $$ = DeclarationNode::newEnum( nullptr, $7, true, true, $3 )->addQualifiers( $5 ); 2688 2695 } … … 2693 2700 | ENUM '(' cfa_abstract_parameter_declaration ')' attribute_list_opt identifier attribute_list_opt 2694 2701 { 2695 if ( $3->storageClasses.any() || $3->type->qualifiers.val != 0 ) { SemanticError( yylloc, "storage-class and CV qualifiers are not meaningful for enumeration constants, which are const." ); } 2702 if ( $3->storageClasses.any() || $3->type->qualifiers.val != 0 ) { 2703 SemanticError( yylloc, "syntax error, storage-class and CV qualifiers are not meaningful for enumeration constants, which are const." ); 2704 } 2696 2705 typedefTable.makeTypedef( *$6 ); 2697 2706 } … … 3166 3175 | IDENTIFIER IDENTIFIER 3167 3176 { IdentifierBeforeIdentifier( *$1.str, *$2.str, " declaration" ); $$ = nullptr; } 3168 | IDENTIFIER type_qualifier // syntax error3177 | IDENTIFIER type_qualifier // invalid syntax rules 3169 3178 { IdentifierBeforeType( *$1.str, "type qualifier" ); $$ = nullptr; } 3170 | IDENTIFIER storage_class // syntax error3179 | IDENTIFIER storage_class // invalid syntax rules 3171 3180 { IdentifierBeforeType( *$1.str, "storage class" ); $$ = nullptr; } 3172 | IDENTIFIER basic_type_name // syntax error3181 | IDENTIFIER basic_type_name // invalid syntax rules 3173 3182 { IdentifierBeforeType( *$1.str, "type" ); $$ = nullptr; } 3174 | IDENTIFIER TYPEDEFname // syntax error3183 | IDENTIFIER TYPEDEFname // invalid syntax rules 3175 3184 { IdentifierBeforeType( *$1.str, "type" ); $$ = nullptr; } 3176 | IDENTIFIER TYPEGENname // syntax error3185 | IDENTIFIER TYPEGENname // invalid syntax rules 3177 3186 { IdentifierBeforeType( *$1.str, "type" ); $$ = nullptr; } 3178 3187 | external_function_definition … … 3209 3218 | type_qualifier_list 3210 3219 { 3211 if ( $1->type->qualifiers.any() ) { SemanticError( yylloc, "CV qualifiers cannot be distributed; only storage-class and forall qualifiers." ); } 3220 if ( $1->type->qualifiers.any() ) { 3221 SemanticError( yylloc, "syntax error, CV qualifiers cannot be distributed; only storage-class and forall qualifiers." ); 3222 } 3212 3223 if ( $1->type->forall ) forall = true; // remember generic type 3213 3224 } … … 3220 3231 | declaration_qualifier_list 3221 3232 { 3222 if ( $1->type && $1->type->qualifiers.any() ) { SemanticError( yylloc, "CV qualifiers cannot be distributed; only storage-class and forall qualifiers." ); } 3233 if ( $1->type && $1->type->qualifiers.any() ) { 3234 SemanticError( yylloc, "syntax error, CV qualifiers cannot be distributed; only storage-class and forall qualifiers." ); 3235 } 3223 3236 if ( $1->type && $1->type->forall ) forall = true; // remember generic type 3224 3237 } … … 3231 3244 | declaration_qualifier_list type_qualifier_list 3232 3245 { 3233 if ( ($1->type && $1->type->qualifiers.any()) || ($2->type && $2->type->qualifiers.any()) ) { SemanticError( yylloc, "CV qualifiers cannot be distributed; only storage-class and forall qualifiers." ); } 3246 if ( ($1->type && $1->type->qualifiers.any()) || ($2->type && $2->type->qualifiers.any()) ) { 3247 SemanticError( yylloc, "syntax error, CV qualifiers cannot be distributed; only storage-class and forall qualifiers." ); 3248 } 3234 3249 if ( ($1->type && $1->type->forall) || ($2->type && $2->type->forall) ) forall = true; // remember generic type 3235 3250 } … … 3262 3277 $$ = $3; forall = false; 3263 3278 if ( $5 ) { 3264 SemanticError( yylloc, " Attributes cannot be associated with function body. Move attribute(s) before \"with\" clause." );3279 SemanticError( yylloc, "syntax error, attributes cannot be associated with function body. Move attribute(s) before \"with\" clause." ); 3265 3280 $$ = nullptr; 3266 3281 } // if -
src/ResolvExpr/Candidate.hpp
rfa5e1aa5 rb7b3e41 91 91 92 92 /// Holdover behaviour from old `findMinCost` -- xxx -- can maybe be eliminated? 93 /* 93 94 static inline void promoteCvtCost( CandidateList & candidates ) { 94 95 for ( CandidateRef & r : candidates ) { … … 96 97 } 97 98 } 99 */ 98 100 99 101 void print( std::ostream & os, const Candidate & cand, Indenter indent = {} ); -
src/ResolvExpr/CandidateFinder.cpp
rfa5e1aa5 rb7b3e41 38 38 #include "typeops.h" // for combos 39 39 #include "Unify.h" 40 #include "WidenMode.h" 40 41 #include "AST/Expr.hpp" 41 42 #include "AST/Node.hpp" … … 749 750 // attempt to narrow based on expected target type 750 751 const ast::Type * returnType = funcType->returns.front(); 751 if ( ! unify( 752 returnType, targetType, funcEnv, funcNeed, funcHave, funcOpen ) 753 ) { 754 // unification failed, do not pursue this candidate 755 return; 752 if ( selfFinder.strictMode ) { 753 if ( ! unifyExact( 754 returnType, targetType, funcEnv, funcNeed, funcHave, funcOpen, noWiden() ) // xxx - is no widening correct? 755 ) { 756 // unification failed, do not pursue this candidate 757 return; 758 } 759 } 760 else { 761 if ( ! unify( 762 returnType, targetType, funcEnv, funcNeed, funcHave, funcOpen ) 763 ) { 764 // unification failed, do not pursue this candidate 765 return; 766 } 756 767 } 757 768 } … … 771 782 for (size_t i=0; i<nParams; ++i) { 772 783 auto obj = funcDecl->params[i].strict_as<ast::ObjectDecl>(); 773 if ( !instantiateArgument( location,784 if ( !instantiateArgument( location, 774 785 funcType->params[i], obj->init, args, results, genStart, symtab)) return; 775 786 } … … 781 792 // matches 782 793 // no default args for indirect calls 783 if ( ! 794 if ( !instantiateArgument( location, 784 795 param, nullptr, args, results, genStart, symtab ) ) return; 785 796 } … … 874 885 875 886 if ( auto structInst = aggrExpr->result.as< ast::StructInstType >() ) { 876 addAggMembers( structInst, aggrExpr, *cand, Cost:: safe, "" );887 addAggMembers( structInst, aggrExpr, *cand, Cost::unsafe, "" ); 877 888 } else if ( auto unionInst = aggrExpr->result.as< ast::UnionInstType >() ) { 878 addAggMembers( unionInst, aggrExpr, *cand, Cost:: safe, "" );889 addAggMembers( unionInst, aggrExpr, *cand, Cost::unsafe, "" ); 879 890 } 880 891 } … … 1007 1018 if ( auto pointer = dynamic_cast< const ast::PointerType * >( funcResult ) ) { 1008 1019 if ( auto function = pointer->base.as< ast::FunctionType >() ) { 1020 // if (!selfFinder.allowVoid && function->returns.empty()) continue; 1009 1021 CandidateRef newFunc{ new Candidate{ *func } }; 1010 1022 newFunc->expr = … … 1018 1030 if ( const ast::EqvClass * clz = func->env.lookup( *inst ) ) { 1019 1031 if ( auto function = clz->bound.as< ast::FunctionType >() ) { 1020 CandidateRef newFunc { new Candidate{ *func } };1032 CandidateRef newFunc( new Candidate( *func ) ); 1021 1033 newFunc->expr = 1022 1034 referenceToRvalueConversion( newFunc->expr, newFunc->cost ); … … 1060 1072 if ( found.empty() && ! errors.isEmpty() ) { throw errors; } 1061 1073 1074 // only keep the best matching intrinsic result to match C semantics (no unexpected narrowing/widening) 1075 // TODO: keep one for each set of argument candidates? 1076 Cost intrinsicCost = Cost::infinity; 1077 CandidateList intrinsicResult; 1078 1062 1079 // Compute conversion costs 1063 1080 for ( CandidateRef & withFunc : found ) { … … 1082 1099 if ( cvtCost != Cost::infinity ) { 1083 1100 withFunc->cvtCost = cvtCost; 1084 candidates.emplace_back( std::move( withFunc ) ); 1085 } 1086 } 1101 withFunc->cost += cvtCost; 1102 auto func = withFunc->expr.strict_as<ast::ApplicationExpr>()->func.as<ast::VariableExpr>(); 1103 if (func && func->var->linkage == ast::Linkage::Intrinsic) { 1104 if (withFunc->cost < intrinsicCost) { 1105 intrinsicResult.clear(); 1106 intrinsicCost = withFunc->cost; 1107 } 1108 if (withFunc->cost == intrinsicCost) { 1109 intrinsicResult.emplace_back(std::move(withFunc)); 1110 } 1111 } 1112 else { 1113 candidates.emplace_back( std::move( withFunc ) ); 1114 } 1115 } 1116 } 1117 spliceBegin( candidates, intrinsicResult ); 1087 1118 found = std::move( candidates ); 1088 1119 1089 1120 // use a new list so that candidates are not examined by addAnonConversions twice 1090 CandidateList winners = findMinCost( found );1091 promoteCvtCost( winners );1121 // CandidateList winners = findMinCost( found ); 1122 // promoteCvtCost( winners ); 1092 1123 1093 1124 // function may return a struct/union value, in which case we need to add candidates 1094 1125 // for implicit conversions to each of the anonymous members, which must happen after 1095 1126 // `findMinCost`, since anon conversions are never the cheapest 1096 for ( const CandidateRef & c : winners) {1127 for ( const CandidateRef & c : found ) { 1097 1128 addAnonConversions( c ); 1098 1129 } 1099 spliceBegin( candidates, winners ); 1100 1101 if ( candidates.empty() && targetType && ! targetType->isVoid() ) { 1130 // would this be too slow when we don't check cost anymore? 1131 spliceBegin( candidates, found ); 1132 1133 if ( candidates.empty() && targetType && ! targetType->isVoid() && !selfFinder.strictMode ) { 1102 1134 // If resolution is unsuccessful with a target type, try again without, since it 1103 1135 // will sometimes succeed when it wouldn't with a target type binding. … … 1140 1172 1141 1173 CandidateFinder finder( context, tenv, toType ); 1174 if (toType->isVoid()) { 1175 finder.allowVoid = true; 1176 } 1177 if ( castExpr->kind == ast::CastExpr::Return ) { 1178 finder.strictMode = true; 1179 finder.find( castExpr->arg, ResolvMode::withAdjustment() ); 1180 1181 // return casts are eliminated (merely selecting an overload, no actual operation) 1182 candidates = std::move(finder.candidates); 1183 } 1142 1184 finder.find( castExpr->arg, ResolvMode::withAdjustment() ); 1143 1185 … … 1145 1187 1146 1188 CandidateList matches; 1189 Cost minExprCost = Cost::infinity; 1190 Cost minCastCost = Cost::infinity; 1147 1191 for ( CandidateRef & cand : finder.candidates ) { 1148 1192 ast::AssertionSet need( cand->need.begin(), cand->need.end() ), have; … … 1176 1220 // count one safe conversion for each value that is thrown away 1177 1221 thisCost.incSafe( discardedValues ); 1178 CandidateRef newCand = std::make_shared<Candidate>( 1179 restructureCast( cand->expr, toType, castExpr->isGenerated ), 1180 copy( cand->env ), std::move( open ), std::move( need ), cand->cost, 1181 cand->cost + thisCost ); 1182 inferParameters( newCand, matches ); 1183 } 1184 } 1185 1186 // select first on argument cost, then conversion cost 1187 CandidateList minArgCost = findMinCost( matches ); 1188 promoteCvtCost( minArgCost ); 1189 candidates = findMinCost( minArgCost ); 1222 // select first on argument cost, then conversion cost 1223 if ( cand->cost < minExprCost || ( cand->cost == minExprCost && thisCost < minCastCost ) ) { 1224 minExprCost = cand->cost; 1225 minCastCost = thisCost; 1226 matches.clear(); 1227 1228 1229 } 1230 // ambiguous case, still output candidates to print in error message 1231 if ( cand->cost == minExprCost && thisCost == minCastCost ) { 1232 CandidateRef newCand = std::make_shared<Candidate>( 1233 restructureCast( cand->expr, toType, castExpr->isGenerated ), 1234 copy( cand->env ), std::move( open ), std::move( need ), cand->cost + thisCost); 1235 // currently assertions are always resolved immediately so this should have no effect. 1236 // if this somehow changes in the future (e.g. delayed by indeterminate return type) 1237 // we may need to revisit the logic. 1238 inferParameters( newCand, matches ); 1239 } 1240 // else skip, better alternatives found 1241 1242 } 1243 } 1244 candidates = std::move(matches); 1245 1246 //CandidateList minArgCost = findMinCost( matches ); 1247 //promoteCvtCost( minArgCost ); 1248 //candidates = findMinCost( minArgCost ); 1190 1249 } 1191 1250 … … 1453 1512 // candidates for true result 1454 1513 CandidateFinder finder2( context, tenv ); 1514 finder2.allowVoid = true; 1455 1515 finder2.find( conditionalExpr->arg2, ResolvMode::withAdjustment() ); 1456 1516 if ( finder2.candidates.empty() ) return; … … 1458 1518 // candidates for false result 1459 1519 CandidateFinder finder3( context, tenv ); 1520 finder3.allowVoid = true; 1460 1521 finder3.find( conditionalExpr->arg3, ResolvMode::withAdjustment() ); 1461 1522 if ( finder3.candidates.empty() ) return; … … 1524 1585 void Finder::postvisit( const ast::ConstructorExpr * ctorExpr ) { 1525 1586 CandidateFinder finder( context, tenv ); 1587 finder.allowVoid = true; 1526 1588 finder.find( ctorExpr->callExpr, ResolvMode::withoutPrune() ); 1527 1589 for ( CandidateRef & r : finder.candidates ) { … … 1640 1702 CandidateFinder finder( context, tenv, toType ); 1641 1703 finder.find( initExpr->expr, ResolvMode::withAdjustment() ); 1704 1705 Cost minExprCost = Cost::infinity; 1706 Cost minCastCost = Cost::infinity; 1642 1707 for ( CandidateRef & cand : finder.candidates ) { 1643 1708 if (reason.code == NotFound) reason.code = NoMatch; … … 1677 1742 // count one safe conversion for each value that is thrown away 1678 1743 thisCost.incSafe( discardedValues ); 1679 CandidateRef newCand = std::make_shared<Candidate>( 1680 new ast::InitExpr{ 1681 initExpr->location, restructureCast( cand->expr, toType ), 1682 initAlt.designation }, 1683 std::move(env), std::move( open ), std::move( need ), cand->cost, thisCost ); 1684 inferParameters( newCand, matches ); 1744 if ( cand->cost < minExprCost || ( cand->cost == minExprCost && thisCost < minCastCost ) ) { 1745 minExprCost = cand->cost; 1746 minCastCost = thisCost; 1747 matches.clear(); 1748 } 1749 // ambiguous case, still output candidates to print in error message 1750 if ( cand->cost == minExprCost && thisCost == minCastCost ) { 1751 CandidateRef newCand = std::make_shared<Candidate>( 1752 new ast::InitExpr{ 1753 initExpr->location, 1754 restructureCast( cand->expr, toType ), 1755 initAlt.designation }, 1756 std::move(env), std::move( open ), std::move( need ), cand->cost + thisCost ); 1757 // currently assertions are always resolved immediately so this should have no effect. 1758 // if this somehow changes in the future (e.g. delayed by indeterminate return type) 1759 // we may need to revisit the logic. 1760 inferParameters( newCand, matches ); 1761 } 1685 1762 } 1686 1763 } … … 1688 1765 1689 1766 // select first on argument cost, then conversion cost 1690 CandidateList minArgCost = findMinCost( matches ); 1691 promoteCvtCost( minArgCost ); 1692 candidates = findMinCost( minArgCost ); 1767 // CandidateList minArgCost = findMinCost( matches ); 1768 // promoteCvtCost( minArgCost ); 1769 // candidates = findMinCost( minArgCost ); 1770 candidates = std::move(matches); 1693 1771 } 1694 1772 … … 1756 1834 auto found = selected.find( mangleName ); 1757 1835 if ( found != selected.end() ) { 1758 if ( newCand->cost < found->second.candidate->cost ) { 1836 // tiebreaking by picking the lower cost on CURRENT expression 1837 // NOTE: this behavior is different from C semantics. 1838 // Specific remediations are performed for C operators at postvisit(UntypedExpr). 1839 // Further investigations may take place. 1840 if ( newCand->cost < found->second.candidate->cost 1841 || (newCand->cost == found->second.candidate->cost && newCand->cvtCost < found->second.candidate->cvtCost) ) { 1759 1842 PRINT( 1760 1843 std::cerr << "cost " << newCand->cost << " beats " … … 1763 1846 1764 1847 found->second = PruneStruct{ newCand }; 1765 } else if ( newCand->cost == found->second.candidate->cost ) {1848 } else if ( newCand->cost == found->second.candidate->cost && newCand->cvtCost == found->second.candidate->cvtCost ) { 1766 1849 // if one of the candidates contains a deleted identifier, can pick the other, 1767 1850 // since deleted expressions should not be ambiguous if there is another option … … 1854 1937 */ 1855 1938 1856 if ( mode.prune ) { 1939 // optimization: don't prune for NameExpr since it never has cost 1940 if ( mode.prune && !dynamic_cast<const ast::NameExpr *>(expr) ) { 1857 1941 // trim candidates to single best one 1858 1942 PRINT( -
src/ResolvExpr/CandidateFinder.hpp
rfa5e1aa5 rb7b3e41 33 33 const ast::TypeEnvironment & env; ///< Substitutions performed in this resolution 34 34 ast::ptr< ast::Type > targetType; ///< Target type for resolution 35 bool strictMode = false; ///< If set to true, requires targetType to be exact match (inside return cast) 36 bool allowVoid = false; ///< If set to true, allow void-returning function calls (only top level, cast to void and first in comma) 35 37 std::set< std::string > otypeKeys; /// different type may map to same key 36 38 -
src/ResolvExpr/CastCost.cc
rfa5e1aa5 rb7b3e41 234 234 if ( typesCompatibleIgnoreQualifiers( src, dst, env ) ) { 235 235 PRINT( std::cerr << "compatible!" << std::endl; ) 236 if (dynamic_cast<const ast::ZeroType *>(dst) || dynamic_cast<const ast::OneType *>(dst)) { 237 return Cost::spec; 238 } 236 239 return Cost::zero; 237 240 } else if ( dynamic_cast< const ast::VoidType * >( dst ) ) { -
src/ResolvExpr/CommonType.cc
rfa5e1aa5 rb7b3e41 697 697 if ( auto basic2 = dynamic_cast< const ast::BasicType * >( type2 ) ) { 698 698 #warning remove casts when `commonTypes` moved to new AST 699 700 /* 699 701 ast::BasicType::Kind kind = (ast::BasicType::Kind)(int)commonTypes[ (BasicType::Kind)(int)basic->kind ][ (BasicType::Kind)(int)basic2->kind ]; 700 702 if ( … … 706 708 result = new ast::BasicType{ kind, basic->qualifiers | basic2->qualifiers }; 707 709 } 710 */ 711 ast::BasicType::Kind kind; 712 if (basic->kind != basic2->kind && !widen.first && !widen.second) return; 713 else if (!widen.first) kind = basic->kind; // widen.second 714 else if (!widen.second) kind = basic2->kind; 715 else kind = (ast::BasicType::Kind)(int)commonTypes[ (BasicType::Kind)(int)basic->kind ][ (BasicType::Kind)(int)basic2->kind ]; 716 // xxx - what does qualifiers even do here?? 717 if ( (basic->qualifiers >= basic2->qualifiers || widen.first) 718 && (basic->qualifiers <= basic2->qualifiers || widen.second) ) { 719 result = new ast::BasicType{ kind, basic->qualifiers | basic2->qualifiers }; 720 } 721 708 722 } else if ( 709 723 dynamic_cast< const ast::ZeroType * >( type2 ) … … 712 726 #warning remove casts when `commonTypes` moved to new AST 713 727 ast::BasicType::Kind kind = (ast::BasicType::Kind)(int)commonTypes[ (BasicType::Kind)(int)basic->kind ][ (BasicType::Kind)(int)ast::BasicType::SignedInt ]; 714 if ( 715 ( ( kind == basic->kind && basic->qualifiers >= type2->qualifiers ) 728 /* 729 if ( // xxx - what does qualifier even do here?? 730 ( ( basic->qualifiers >= type2->qualifiers ) 716 731 || widen.first ) 717 && ( (kind != basic->kind && basic->qualifiers <= type2->qualifiers )732 && ( ( /* kind != basic->kind && basic->qualifiers <= type2->qualifiers ) 718 733 || widen.second ) 719 ) { 720 result = new ast::BasicType{ kind, basic->qualifiers | type2->qualifiers }; 734 ) 735 */ 736 if (widen.second) { 737 result = new ast::BasicType{ basic->kind, basic->qualifiers | type2->qualifiers }; 721 738 } 722 739 } else if ( const ast::EnumInstType * enumInst = dynamic_cast< const ast::EnumInstType * >( type2 ) ) { … … 746 763 auto entry = open.find( *var ); 747 764 if ( entry != open.end() ) { 765 // if (tenv.lookup(*var)) { 748 766 ast::AssertionSet need, have; 749 767 if ( ! tenv.bindVar( … … 1017 1035 void postvisit( const ast::TraitInstType * ) {} 1018 1036 1019 void postvisit( const ast::TypeInstType * inst) {}1020 1021 void postvisit( const ast::TupleType * tuple ) {1037 void postvisit( const ast::TypeInstType * ) {} 1038 1039 void postvisit( const ast::TupleType * tuple ) { 1022 1040 tryResolveWithTypedEnum( tuple ); 1023 1041 } -
src/ResolvExpr/ConversionCost.cc
rfa5e1aa5 rb7b3e41 702 702 703 703 cost = costCalc( refType->base, dst, srcIsLvalue, symtab, env ); 704 705 // xxx - should qualifiers be considered in pass-by-value? 706 /* 704 707 if ( refType->base->qualifiers == dst->qualifiers ) { 705 708 cost.incReference(); … … 709 712 cost.incUnsafe(); 710 713 } 714 */ 715 cost.incReference(); 711 716 } 712 717 … … 792 797 cost.incSign( signMatrix[ ast::BasicType::SignedInt ][ dstAsBasic->kind ] ); 793 798 } 799 // this has the effect of letting any expr such as x+0, x+1 to be typed 800 // the same as x, instead of at least int. are we willing to sacrifice this little 801 // bit of coherence with C? 802 // TODO: currently this does not work when no zero/one overloads exist. Find a fix for it. 803 // cost = Cost::zero; 794 804 } else if ( dynamic_cast< const ast::PointerType * >( dst ) ) { 795 805 cost = Cost::zero; 796 806 // +1 for zero_t ->, +1 for disambiguation 797 807 cost.incSafe( maxIntCost + 2 ); 808 // assuming 0p is supposed to be used for pointers? 798 809 } 799 810 } … … 804 815 cost = Cost::zero; 805 816 } else if ( const ast::BasicType * dstAsBasic = 806 dynamic_cast< const ast::BasicType * >( dst ) ) { 817 dynamic_cast< const ast::BasicType * >( dst ) ) { 807 818 int tableResult = costMatrix[ ast::BasicType::SignedInt ][ dstAsBasic->kind ]; 808 819 if ( -1 == tableResult ) { … … 813 824 cost.incSign( signMatrix[ ast::BasicType::SignedInt ][ dstAsBasic->kind ] ); 814 825 } 826 827 // cost = Cost::zero; 815 828 } 816 829 } -
src/ResolvExpr/CurrentObject.cc
rfa5e1aa5 rb7b3e41 689 689 690 690 auto arg = eval( expr ); 691 index = arg.first; 691 assertf( arg.hasKnownValue, "Non-evaluable expression made it to IndexIterator" ); 692 index = arg.knownValue; 692 693 693 694 // if ( auto constExpr = dynamic_cast< const ConstantExpr * >( expr ) ) { … … 728 729 size_t getSize( const Expr * expr ) { 729 730 auto res = eval( expr ); 730 if ( !res. second) {731 if ( !res.hasKnownValue ) { 731 732 SemanticError( location, toString( "Array designator must be a constant expression: ", expr ) ); 732 733 } 733 return res. first;734 return res.knownValue; 734 735 } 735 736 -
src/ResolvExpr/FindOpenVars.cc
rfa5e1aa5 rb7b3e41 21 21 #include "AST/Pass.hpp" 22 22 #include "AST/Type.hpp" 23 #include "AST/TypeEnvironment.hpp" 23 24 #include "Common/PassVisitor.h" 24 25 #include "SynTree/Declaration.h" // for TypeDecl, DeclarationWithType (ptr ... 25 26 #include "SynTree/Type.h" // for Type, Type::ForallList, ArrayType 27 28 #include <iostream> 26 29 27 30 namespace ResolvExpr { … … 102 105 ast::AssertionSet & need; 103 106 ast::AssertionSet & have; 107 ast::TypeEnvironment & env; 104 108 bool nextIsOpen; 105 109 106 110 FindOpenVars_new( 107 111 ast::OpenVarSet & o, ast::OpenVarSet & c, ast::AssertionSet & n, 108 ast::AssertionSet & h, FirstMode firstIsOpen )109 : open( o ), closed( c ), need( n ), have( h ), nextIsOpen( firstIsOpen ) {}112 ast::AssertionSet & h, ast::TypeEnvironment & env, FirstMode firstIsOpen ) 113 : open( o ), closed( c ), need( n ), have( h ), env (env), nextIsOpen( firstIsOpen ) {} 110 114 111 115 void previsit( const ast::FunctionType * type ) { 112 116 // mark open/closed variables 113 117 if ( nextIsOpen ) { 118 // trying to remove this from resolver. 119 // occasionally used in other parts so not deleting right now. 120 121 // insert open variables unbound to environment. 122 env.add(type->forall); 123 114 124 for ( auto & decl : type->forall ) { 115 125 open[ *decl ] = ast::TypeData{ decl->base }; … … 137 147 void findOpenVars( 138 148 const ast::Type * type, ast::OpenVarSet & open, ast::OpenVarSet & closed, 139 ast::AssertionSet & need, ast::AssertionSet & have, FirstMode firstIsOpen ) {140 ast::Pass< FindOpenVars_new > finder{ open, closed, need, have, firstIsOpen };149 ast::AssertionSet & need, ast::AssertionSet & have, ast::TypeEnvironment & env, FirstMode firstIsOpen ) { 150 ast::Pass< FindOpenVars_new > finder{ open, closed, need, have, env, firstIsOpen }; 141 151 type->accept( finder ); 152 153 if (!closed.empty()) { 154 std::cerr << "closed: "; 155 for (auto& i : closed) { 156 std::cerr << i.first.base->location << ":" << i.first.base->name << ' '; 157 } 158 std::cerr << std::endl; 159 } 142 160 } 143 161 } // namespace ResolvExpr -
src/ResolvExpr/FindOpenVars.h
rfa5e1aa5 rb7b3e41 33 33 void findOpenVars( 34 34 const ast::Type * type, ast::OpenVarSet & open, ast::OpenVarSet & closed, 35 ast::AssertionSet & need, ast::AssertionSet & have, FirstMode firstIsOpen );35 ast::AssertionSet & need, ast::AssertionSet & have, ast::TypeEnvironment & env, FirstMode firstIsOpen ); 36 36 } // namespace ResolvExpr 37 37 -
src/ResolvExpr/Resolver.cc
rfa5e1aa5 rb7b3e41 1011 1011 ast::TypeEnvironment env; 1012 1012 CandidateFinder finder( context, env ); 1013 finder.allowVoid = true; 1013 1014 finder.find( untyped, recursion_level == 1 ? mode.atTopLevel() : mode ); 1014 1015 --recursion_level; … … 1054 1055 1055 1056 // promote candidate.cvtCost to .cost 1056 promoteCvtCost( winners );1057 // promoteCvtCost( winners ); 1057 1058 1058 1059 // produce ambiguous errors, if applicable … … 1106 1107 1107 1108 /// Removes cast to type of argument (unlike StripCasts, also handles non-generated casts) 1108 void removeExtraneousCast( ast::ptr<ast::Expr> & expr , const ast::SymbolTable & symtab) {1109 void removeExtraneousCast( ast::ptr<ast::Expr> & expr ) { 1109 1110 if ( const ast::CastExpr * castExpr = expr.as< ast::CastExpr >() ) { 1110 1111 if ( typesCompatible( castExpr->arg->result, castExpr->result ) ) { … … 1196 1197 ast::ptr< ast::Expr > castExpr = new ast::CastExpr{ untyped, type }; 1197 1198 ast::ptr< ast::Expr > newExpr = findSingleExpression( castExpr, context ); 1198 removeExtraneousCast( newExpr , context.symtab);1199 removeExtraneousCast( newExpr ); 1199 1200 return newExpr; 1200 1201 } … … 1261 1262 static size_t traceId; 1262 1263 Resolver_new( const ast::TranslationGlobal & global ) : 1264 ast::WithSymbolTable(ast::SymbolTable::ErrorDetection::ValidateOnAdd), 1263 1265 context{ symtab, global } {} 1264 1266 Resolver_new( const ResolveContext & context ) : … … 1340 1342 auto mutAttr = mutate(attr); 1341 1343 mutAttr->params.front() = resolved; 1342 if (! result. second) {1344 if (! result.hasKnownValue) { 1343 1345 SemanticWarning(loc, Warning::GccAttributes, 1344 1346 toCString( name, " priorities must be integers from 0 to 65535 inclusive: ", arg ) ); 1345 1347 } 1346 1348 else { 1347 auto priority = result. first;1349 auto priority = result.knownValue; 1348 1350 if (priority < 101) { 1349 1351 SemanticWarning(loc, Warning::GccAttributes, … … 2040 2042 const ast::Type * initContext = currentObject.getCurrentType(); 2041 2043 2042 removeExtraneousCast( newExpr , symtab);2044 removeExtraneousCast( newExpr ); 2043 2045 2044 2046 // check if actual object's type is char[] -
src/ResolvExpr/SatisfyAssertions.cpp
rfa5e1aa5 rb7b3e41 16 16 #include "SatisfyAssertions.hpp" 17 17 18 #include <iostream> 18 19 #include <algorithm> 19 20 #include <cassert> … … 45 46 #include "SymTab/Mangler.h" 46 47 48 49 47 50 namespace ResolvExpr { 48 51 … … 65 68 ast::AssertionSet && h, ast::AssertionSet && n, ast::OpenVarSet && o, ast::UniqueId rs ) 66 69 : cdata( c ), adjType( at ), env( std::move( e ) ), have( std::move( h ) ), 67 need( std::move( n ) ), open( std::move( o ) ), resnSlot( rs ) {} 70 need( std::move( n ) ), open( std::move( o ) ), resnSlot( rs ) { 71 if (!have.empty()) { 72 // std::cerr << c.id->location << ':' << c.id->name << std::endl; // I think this was debugging code so I commented it 73 } 74 } 68 75 }; 69 76 … … 139 146 }; 140 147 141 /// Adds a captured assertion to the symbol table 142 void addToSymbolTable( const ast::AssertionSet & have, ast::SymbolTable & symtab ) { 143 for ( auto & i : have ) { 144 if ( i.second.isUsed ) { symtab.addId( i.first->var ); } 145 } 146 } 148 enum AssertionResult {Fail, Skip, Success} ; 147 149 148 150 /// Binds a single assertion, updating satisfaction state … … 155 157 "Assertion candidate does not have a unique ID: %s", toString( candidate ).c_str() ); 156 158 157 ast::Expr * varExpr = match.cdata.combine( cand->expr->location, cand->c vtCost );159 ast::Expr * varExpr = match.cdata.combine( cand->expr->location, cand->cost ); 158 160 varExpr->result = match.adjType; 159 161 if ( match.resnSlot ) { varExpr->inferred.resnSlots().emplace_back( match.resnSlot ); } … … 165 167 166 168 /// Satisfy a single assertion 167 bool satisfyAssertion( ast::AssertionList::value_type & assn, SatState & sat, bool allowConversion = false, bool skipUnbound = false) {169 AssertionResult satisfyAssertion( ast::AssertionList::value_type & assn, SatState & sat, bool skipUnbound = false) { 168 170 // skip unused assertions 169 if ( ! assn.second.isUsed ) return true; 171 // static unsigned int cnt = 0; // I think this was debugging code so I commented it 172 if ( ! assn.second.isUsed ) return AssertionResult::Success; 173 174 // if (assn.first->var->name[1] == '|') std::cerr << ++cnt << std::endl; // I think this was debugging code so I commented it 170 175 171 176 // find candidates that unify with the desired type 172 AssnCandidateList matches ;177 AssnCandidateList matches, inexactMatches; 173 178 174 179 std::vector<ast::SymbolTable::IdData> candidates; … … 179 184 .strict_as<ast::FunctionType>()->params[0] 180 185 .strict_as<ast::ReferenceType>()->base; 181 sat.cand->env.apply(thisArgType); 186 // sat.cand->env.apply(thisArgType); 187 188 if (auto inst = thisArgType.as<ast::TypeInstType>()) { 189 auto cls = sat.cand->env.lookup(*inst); 190 if (cls && cls->bound) thisArgType = cls->bound; 191 } 182 192 183 193 std::string otypeKey = ""; 184 194 if (thisArgType.as<ast::PointerType>()) otypeKey = Mangle::Encoding::pointer; 185 195 else if (!isUnboundType(thisArgType)) otypeKey = Mangle::mangle(thisArgType, Mangle::Type | Mangle::NoGenericParams); 186 else if (skipUnbound) return false;196 else if (skipUnbound) return AssertionResult::Skip; 187 197 188 198 candidates = sat.symtab.specialLookupId(kind, otypeKey); … … 212 222 213 223 ast::OpenVarSet closed; 214 findOpenVars( toType, newOpen, closed, newNeed, have, FirstClosed ); 215 findOpenVars( adjType, newOpen, closed, newNeed, have, FirstOpen ); 216 if ( allowConversion ) { 224 // findOpenVars( toType, newOpen, closed, newNeed, have, FirstClosed ); 225 findOpenVars( adjType, newOpen, closed, newNeed, have, newEnv, FirstOpen ); 226 ast::TypeEnvironment tempNewEnv {newEnv}; 227 228 if ( unifyExact( toType, adjType, tempNewEnv, newNeed, have, newOpen, WidenMode {true, true} ) ) { 229 // set up binding slot for recursive assertions 230 ast::UniqueId crntResnSlot = 0; 231 if ( ! newNeed.empty() ) { 232 crntResnSlot = ++globalResnSlot; 233 for ( auto & a : newNeed ) { a.second.resnSlot = crntResnSlot; } 234 } 235 236 matches.emplace_back( 237 cdata, adjType, std::move( tempNewEnv ), std::move( have ), std::move( newNeed ), 238 std::move( newOpen ), crntResnSlot ); 239 } 240 else if ( matches.empty() ) { 241 // restore invalidated env 242 // newEnv = sat.cand->env; 243 // newNeed.clear(); 217 244 if ( auto c = commonType( toType, adjType, newEnv, newNeed, have, newOpen, WidenMode {true, true} ) ) { 218 245 // set up binding slot for recursive assertions … … 223 250 } 224 251 225 matches.emplace_back(252 inexactMatches.emplace_back( 226 253 cdata, adjType, std::move( newEnv ), std::move( have ), std::move( newNeed ), 227 254 std::move( newOpen ), crntResnSlot ); 228 255 } 229 256 } 230 else {231 if ( unifyExact( toType, adjType, newEnv, newNeed, have, newOpen, WidenMode {true, true} ) ) {232 // set up binding slot for recursive assertions233 ast::UniqueId crntResnSlot = 0;234 if ( ! newNeed.empty() ) {235 crntResnSlot = ++globalResnSlot;236 for ( auto & a : newNeed ) { a.second.resnSlot = crntResnSlot; }237 }238 239 matches.emplace_back(240 cdata, adjType, std::move( newEnv ), std::move( have ), std::move( newNeed ),241 std::move( newOpen ), crntResnSlot );242 }243 }244 257 } 245 258 246 259 // break if no satisfying match 247 if ( matches.empty() ) return false; 260 if ( matches.empty() ) matches = std::move(inexactMatches); 261 if ( matches.empty() ) return AssertionResult::Fail; 248 262 249 263 // defer if too many satisfying matches 250 264 if ( matches.size() > 1 ) { 251 265 sat.deferred.emplace_back( assn.first, assn.second, std::move( matches ) ); 252 return true;266 return AssertionResult::Success; 253 267 } 254 268 255 269 // otherwise bind unique match in ongoing scope 256 270 AssnCandidate & match = matches.front(); 257 addToSymbolTable( match.have, sat.symtab );271 // addToSymbolTable( match.have, sat.symtab ); 258 272 sat.newNeed.insert( match.need.begin(), match.need.end() ); 259 273 sat.cand->env = std::move( match.env ); … … 261 275 262 276 bindAssertion( assn.first, assn.second, sat.cand, match, sat.inferred ); 263 return true;277 return AssertionResult::Success; 264 278 } 265 279 … … 438 452 // for each current mutually-compatible set of assertions 439 453 for ( SatState & sat : sats ) { 440 bool allowConversion = false;441 454 // stop this branch if a better option is already found 442 455 auto it = thresholds.find( pruneKey( *sat.cand ) ); … … 447 460 for (unsigned resetCount = 0; ; ++resetCount) { 448 461 ast::AssertionList next; 449 resetTyVarRenaming();450 462 // make initial pass at matching assertions 451 463 for ( auto & assn : sat.need ) { 464 resetTyVarRenaming(); 452 465 // fail early if any assertion is not satisfiable 453 if ( ! satisfyAssertion( assn, sat, allowConversion, !next.empty() ) ) { 454 next.emplace_back(assn); 455 // goto nextSat; 456 } 457 } 458 // success 459 if (next.empty()) break; 460 // fail if nothing resolves 461 else if (next.size() == sat.need.size()) { 462 if (allowConversion) { 466 auto result = satisfyAssertion( assn, sat, !next.empty() ); 467 if ( result == AssertionResult::Fail ) { 463 468 Indenter tabs{ 3 }; 464 469 std::ostringstream ss; … … 466 471 print( ss, *sat.cand, ++tabs ); 467 472 ss << (tabs-1) << "Could not satisfy assertion:\n"; 468 ast::print( ss, next[0].first, tabs );473 ast::print( ss, assn.first, tabs ); 469 474 470 475 errors.emplace_back( ss.str() ); 471 476 goto nextSat; 472 477 } 473 474 else { 475 allowConversion = true; 476 continue; 477 } 478 } 479 allowConversion = false; 478 else if ( result == AssertionResult::Skip ) { 479 next.emplace_back(assn); 480 // goto nextSat; 481 } 482 } 483 // success 484 if (next.empty()) break; 485 480 486 sat.need = std::move(next); 481 487 } … … 531 537 sat.cand->expr, std::move( compat.env ), std::move( compat.open ), 532 538 ast::AssertionSet{} /* need moved into satisfaction state */, 533 sat.cand->cost , sat.cand->cvtCost);539 sat.cand->cost ); 534 540 535 541 ast::AssertionSet nextNewNeed{ sat.newNeed }; … … 544 550 for ( DeferRef r : compat.assns ) { 545 551 AssnCandidate match = r.match; 546 addToSymbolTable( match.have, nextSymtab );552 // addToSymbolTable( match.have, nextSymtab ); 547 553 nextNewNeed.insert( match.need.begin(), match.need.end() ); 548 554 -
src/ResolvExpr/Unify.cc
rfa5e1aa5 rb7b3e41 160 160 env.apply( newSecond ); 161 161 162 findOpenVars( newFirst, open, closed, need, have, FirstClosed );163 findOpenVars( newSecond, open, closed, need, have, FirstOpen );162 // findOpenVars( newFirst, open, closed, need, have, FirstClosed ); 163 findOpenVars( newSecond, open, closed, need, have, newEnv, FirstOpen ); 164 164 165 165 return unifyExact(newFirst, newSecond, newEnv, need, have, open, noWiden() ); … … 964 964 // check that the other type is compatible and named the same 965 965 auto otherInst = dynamic_cast< const XInstType * >( other ); 966 if (otherInst && inst->name == otherInst->name) this->result = otherInst; 966 if (otherInst && inst->name == otherInst->name) 967 this->result = otherInst; 967 968 return otherInst; 968 969 } … … 1049 1050 1050 1051 void postvisit( const ast::TypeInstType * typeInst ) { 1051 assert( open.find( *typeInst ) == open.end() ); 1052 handleRefType( typeInst, type2 ); 1052 // assert( open.find( *typeInst ) == open.end() ); 1053 auto otherInst = dynamic_cast< const ast::TypeInstType * >( type2 ); 1054 if (otherInst && typeInst->name == otherInst->name) 1055 this->result = otherInst; 1056 // return otherInst; 1053 1057 } 1054 1058 … … 1161 1165 ) { 1162 1166 ast::OpenVarSet closed; 1163 findOpenVars( type1, open, closed, need, have, FirstClosed );1164 findOpenVars( type2, open, closed, need, have, FirstOpen );1167 // findOpenVars( type1, open, closed, need, have, FirstClosed ); 1168 findOpenVars( type2, open, closed, need, have, env, FirstOpen ); 1165 1169 return unifyInexact( 1166 1170 type1, type2, env, need, have, open, WidenMode{ true, true }, common ); … … 1179 1183 entry1 = var1 ? open.find( *var1 ) : open.end(), 1180 1184 entry2 = var2 ? open.find( *var2 ) : open.end(); 1181 bool isopen1 = entry1 != open.end(); 1182 bool isopen2 = entry2 != open.end(); 1183 1185 // bool isopen1 = entry1 != open.end(); 1186 // bool isopen2 = entry2 != open.end(); 1187 bool isopen1 = var1 && env.lookup(*var1); 1188 bool isopen2 = var2 && env.lookup(*var2); 1189 1190 /* 1184 1191 if ( isopen1 && isopen2 ) { 1185 1192 if ( entry1->second.kind != entry2->second.kind ) return false; … … 1190 1197 return env.bindVar( var1, type2, entry1->second, need, have, open, widen ); 1191 1198 } else if ( isopen2 ) { 1192 return env.bindVar( var2, type1, entry2->second, need, have, open, widen ); 1193 } else { 1199 return env.bindVar( var2, type1, entry2->second, need, have, open, widen, symtab ); 1200 } */ 1201 if ( isopen1 && isopen2 ) { 1202 if ( var1->base->kind != var2->base->kind ) return false; 1203 return env.bindVarToVar( 1204 var1, var2, ast::TypeData{ var1->base->kind, var1->base->sized||var2->base->sized }, need, have, 1205 open, widen ); 1206 } else if ( isopen1 ) { 1207 return env.bindVar( var1, type2, ast::TypeData{var1->base}, need, have, open, widen ); 1208 } else if ( isopen2 ) { 1209 return env.bindVar( var2, type1, ast::TypeData{var2->base}, need, have, open, widen ); 1210 }else { 1194 1211 return ast::Pass<Unify_new>::read( 1195 1212 type1, type2, env, need, have, open, widen ); 1196 1213 } 1214 1197 1215 } 1198 1216 -
src/SynTree/Expression.cc
rfa5e1aa5 rb7b3e41 267 267 } 268 268 269 CastExpr::CastExpr( Expression * arg, Type * toType, bool isGenerated ) : arg(arg), isGenerated( isGenerated ) {269 CastExpr::CastExpr( Expression * arg, Type * toType, bool isGenerated, CastKind kind ) : arg(arg), isGenerated( isGenerated ), kind( kind ) { 270 270 set_result(toType); 271 271 } 272 272 273 CastExpr::CastExpr( Expression * arg, bool isGenerated ) : arg(arg), isGenerated( isGenerated ) {273 CastExpr::CastExpr( Expression * arg, bool isGenerated, CastKind kind ) : arg(arg), isGenerated( isGenerated ), kind( kind ) { 274 274 set_result( new VoidType( Type::Qualifiers() ) ); 275 275 } 276 276 277 CastExpr::CastExpr( const CastExpr & other ) : Expression( other ), arg( maybeClone( other.arg ) ), isGenerated( other.isGenerated ) {277 CastExpr::CastExpr( const CastExpr & other ) : Expression( other ), arg( maybeClone( other.arg ) ), isGenerated( other.isGenerated ), kind( other.kind ) { 278 278 } 279 279 -
src/SynTree/Expression.h
rfa5e1aa5 rb7b3e41 271 271 bool isGenerated = true; 272 272 273 CastExpr( Expression * arg, bool isGenerated = true ); 274 CastExpr( Expression * arg, Type * toType, bool isGenerated = true ); 273 enum CastKind { 274 Default, // C 275 Coerce, // reinterpret cast 276 Return // overload selection 277 }; 278 279 CastKind kind = Default; 280 281 CastExpr( Expression * arg, bool isGenerated = true, CastKind kind = Default ); 282 CastExpr( Expression * arg, Type * toType, bool isGenerated = true, CastKind kind = Default ); 275 283 CastExpr( Expression * arg, void * ) = delete; // prevent accidentally passing pointers for isGenerated in the first constructor 276 284 CastExpr( const CastExpr & other ); -
src/Tuples/TupleAssignment.cc
rfa5e1aa5 rb7b3e41 679 679 680 680 ResolvExpr::CandidateFinder finder( crntFinder.context, matcher->env ); 681 finder.allowVoid = true; 681 682 682 683 try { -
src/Validate/Autogen.cpp
rfa5e1aa5 rb7b3e41 321 321 void FuncGenerator::produceDecl( const ast::FunctionDecl * decl ) { 322 322 assert( nullptr != decl->stmts ); 323 assert( decl->type_params.size() == getGenericParams( type ).size() ); 323 324 324 325 definitions.push_back( decl ); … … 356 357 decl->init = nullptr; 357 358 splice( assertions, decl->assertions ); 358 oldToNew.emplace( std::make_pair( old_param, decl ));359 oldToNew.emplace( old_param, decl ); 359 360 type_params.push_back( decl ); 360 361 } … … 522 523 InitTweak::InitExpander_new srcParam( src ); 523 524 // Assign to destination. 524 ast:: Expr * dstSelect = new ast::MemberExpr(525 ast::MemberExpr * dstSelect = new ast::MemberExpr( 525 526 location, 526 527 field, … … 574 575 } 575 576 576 ast:: Expr * srcSelect = (srcParam) ? new ast::MemberExpr(577 ast::MemberExpr * srcSelect = (srcParam) ? new ast::MemberExpr( 577 578 location, field, new ast::VariableExpr( location, srcParam ) 578 579 ) : nullptr; -
src/Validate/HoistStruct.cpp
rfa5e1aa5 rb7b3e41 18 18 #include <sstream> 19 19 20 #include "AST/DeclReplacer.hpp" 20 21 #include "AST/Pass.hpp" 21 22 #include "AST/TranslationUnit.hpp" 23 #include "AST/Vector.hpp" 22 24 23 25 namespace Validate { … … 51 53 template<typename AggrDecl> 52 54 AggrDecl const * postAggregate( AggrDecl const * ); 55 template<typename InstType> 56 InstType const * preCollectionInstType( InstType const * type ); 53 57 54 58 ast::AggregateDecl const * parent = nullptr; … … 66 70 qualifiedName( decl, ss ); 67 71 return ss.str(); 72 } 73 74 void extendParams( ast::vector<ast::TypeDecl> & dstParams, 75 ast::vector<ast::TypeDecl> const & srcParams ) { 76 if ( srcParams.empty() ) return; 77 78 ast::DeclReplacer::TypeMap newToOld; 79 ast::vector<ast::TypeDecl> params; 80 for ( ast::ptr<ast::TypeDecl> const & srcParam : srcParams ) { 81 ast::TypeDecl * dstParam = ast::deepCopy( srcParam.get() ); 82 dstParam->init = nullptr; 83 newToOld.emplace( srcParam, dstParam ); 84 for ( auto assertion : dstParam->assertions ) { 85 assertion = ast::DeclReplacer::replace( assertion, newToOld ); 86 } 87 params.emplace_back( dstParam ); 88 } 89 spliceBegin( dstParams, params ); 68 90 } 69 91 … … 74 96 mut->parent = parent; 75 97 mut->name = qualifiedName( mut ); 76 return mut;77 } else {78 GuardValue( parent ) = decl;79 returndecl;80 }98 extendParams( mut->params, parent->params ); 99 decl = mut; 100 } 101 GuardValue( parent ) = decl; 102 return decl; 81 103 } 82 104 … … 112 134 } 113 135 136 ast::AggregateDecl const * commonParent( 137 ast::AggregateDecl const * lhs, ast::AggregateDecl const * rhs ) { 138 for ( auto outer = lhs ; outer ; outer = outer->parent ) { 139 for ( auto inner = rhs ; inner ; inner = inner->parent ) { 140 if ( outer == inner ) { 141 return outer; 142 } 143 } 144 } 145 return nullptr; 146 } 147 148 template<typename InstType> 149 InstType const * HoistStructCore::preCollectionInstType( InstType const * type ) { 150 if ( !type->base->parent ) return type; 151 if ( type->base->params.empty() ) return type; 152 153 InstType * mut = ast::mutate( type ); 154 ast::AggregateDecl const * parent = 155 commonParent( this->parent, mut->base->parent ); 156 assert( parent ); 157 158 std::vector<ast::ptr<ast::Expr>> args; 159 for ( const ast::ptr<ast::TypeDecl> & param : parent->params ) { 160 args.emplace_back( new ast::TypeExpr( param->location, 161 new ast::TypeInstType( param ) 162 ) ); 163 } 164 spliceBegin( mut->params, args ); 165 return mut; 166 } 167 114 168 template<typename InstType> 115 169 InstType const * preInstType( InstType const * type ) { … … 121 175 122 176 ast::StructInstType const * HoistStructCore::previsit( ast::StructInstType const * type ) { 123 return preInstType( type);177 return preInstType( preCollectionInstType( type ) ); 124 178 } 125 179 126 180 ast::UnionInstType const * HoistStructCore::previsit( ast::UnionInstType const * type ) { 127 return preInstType( type);181 return preInstType( preCollectionInstType( type ) ); 128 182 } 129 183 -
src/Virtual/VirtualDtor.cpp
rfa5e1aa5 rb7b3e41 146 146 147 147 CompoundStmt * dtorBody = mutate( decl->stmts.get() ); 148 // Adds the following to the endof any actor/message dtor:148 // Adds the following to the start of any actor/message dtor: 149 149 // __CFA_dtor_shutdown( this ); 150 dtorBody->push_front( new ExprStmt( 151 decl->location, 152 new UntypedExpr ( 153 decl->location, 154 new NameExpr( decl->location, "__CFA_dtor_shutdown" ), 155 { 156 new NameExpr( decl->location, decl->params.at(0)->name ) 157 } 158 ) 159 )); 150 dtorBody->push_front( 151 new IfStmt( decl->location, 152 new UntypedExpr ( 153 decl->location, 154 new NameExpr( decl->location, "__CFA_dtor_shutdown" ), 155 { 156 new NameExpr( decl->location, decl->params.at(0)->name ) 157 } 158 ), 159 new ReturnStmt( decl->location, nullptr ) 160 ) 161 ); 160 162 return; 161 163 } -
src/main.cc
rfa5e1aa5 rb7b3e41 28 28 #include <list> // for list 29 29 #include <string> // for char_traits, operator<< 30 31 using namespace std;32 30 33 31 #include "AST/Convert.hpp" … … 88 86 #include "Virtual/VirtualDtor.hpp" // for implementVirtDtors 89 87 88 using namespace std; 89 90 90 static void NewPass( const char * const name ) { 91 91 Stats::Heap::newPass( name ); … … 335 335 336 336 PASS( "Fix Qualified Types", Validate::fixQualifiedTypes, transUnit ); 337 PASS( "Eliminate Typedef", Validate::eliminateTypedef, transUnit ); 337 338 PASS( "Hoist Struct", Validate::hoistStruct, transUnit ); 338 PASS( "Eliminate Typedef", Validate::eliminateTypedef, transUnit );339 339 PASS( "Validate Generic Parameters", Validate::fillGenericParameters, transUnit ); 340 340 PASS( "Translate Dimensions", Validate::translateDimensionParameters, transUnit );
Note:
See TracChangeset
for help on using the changeset viewer.