Changes in / [4da6a6c:2f26687a]
- Files:
-
- 12 edited
Legend:
- Unmodified
- Added
- Removed
-
doc/LaTeXmacros/common.tex
r4da6a6c r2f26687a 40 40 \newcommand{\CC}{\rm C\kern-.1em\hbox{+\kern-.25em+}\xspace} % CC symbolic name 41 41 \newcommand{\CCeleven}{\rm C\kern-.1em\hbox{+\kern-.25em+}11\xspace} % C++11 symbolic name 42 \newcommand{\CCseventeen}{\rm C\kern-.1em\hbox{+\kern-.25em+}17\xspace} % C++17 symbolic name 42 43 \newcommand{\Celeven}{C11\xspace} % C11 symbolic name 43 44 \newcommand{\Csharp}{C\raisebox{0.4ex}{\#}\xspace} % C# symbolic name -
src/GenPoly/Specialize.cc
r4da6a6c r2f26687a 77 77 } 78 78 79 /// True if both types have the same structure, but not necessarily the same types. 80 /// That is, either both types are tuple types with the same size (recursively), or 81 /// both are not tuple types. 82 bool matchingTupleStructure( Type * t1, Type * t2 ) { 83 TupleType * tuple1 = dynamic_cast< TupleType * >( t1 ); 84 TupleType * tuple2 = dynamic_cast< TupleType * >( t2 ); 85 if ( tuple1 && tuple2 ) { 86 if ( tuple1->size() != tuple2->size() ) return false; 87 for ( auto types : group_iterate( tuple1->get_types(), tuple2->get_types() ) ) { 88 if ( ! matchingTupleStructure( std::get<0>( types ), std::get<1>( types ) ) ) return false; 89 } 90 return true; 91 } else if ( ! tuple1 && ! tuple2 ) return true; 92 return false; 93 } 94 79 95 bool needsTupleSpecialization( Type *formalType, Type *actualType, TypeSubstitution *env ) { 80 if ( FunctionType * ftype = getFunctionType( formalType ) ) { 81 return ftype->isTtype(); 96 // Needs tuple specialization if the structure of the formal type and actual type do not match. 97 // This is the case if the formal type has ttype polymorphism, or if the structure of tuple types 98 // between the function do not match exactly. 99 if ( FunctionType * fftype = getFunctionType( formalType ) ) { 100 if ( fftype->isTtype() ) return true; 101 FunctionType * aftype = getFunctionType( actualType ); 102 assertf( aftype, "formal type is a function type, but actual type is not." ); 103 if ( fftype->get_parameters().size() != aftype->get_parameters().size() ) return true; 104 for ( auto params : group_iterate( fftype->get_parameters(), aftype->get_parameters() ) ) { 105 DeclarationWithType * formal = std::get<0>(params); 106 DeclarationWithType * actual = std::get<1>(params); 107 if ( ! matchingTupleStructure( formal->get_type(), actual->get_type() ) ) return true; 108 } 82 109 } 83 110 return false; … … 110 137 } 111 138 112 /// restructures arg to match the structure of a single formal parameter. Assumes that atomic types are compatible (as the Resolver should have ensured this) 113 template< typename OutIterator > 114 void matchOneFormal( Expression * arg, unsigned & idx, Type * formal, OutIterator out ) { 115 if ( TupleType * tupleType = dynamic_cast< TupleType * >( formal ) ) { 139 /// restructures the arguments to match the structure of the formal parameters of the actual function. 140 /// [begin, end) are the exploded arguments. 141 template< typename Iterator, typename OutIterator > 142 void structureArg( Type * type, Iterator & begin, Iterator end, OutIterator out ) { 143 if ( TupleType * tuple = dynamic_cast< TupleType * >( type ) ) { 116 144 std::list< Expression * > exprs; 117 for ( Type * t : *tuple Type) {118 matchOneFormal( arg, idx, t, back_inserter( exprs ) );145 for ( Type * t : *tuple ) { 146 structureArg( t, begin, end, back_inserter( exprs ) ); 119 147 } 120 148 *out++ = new TupleExpr( exprs ); 121 149 } else { 122 *out++ = new TupleIndexExpr( arg->clone(), idx++ ); 123 } 124 } 125 126 /// restructures the ttype argument to match the structure of the formal parameters of the actual function. 127 /// [begin, end) are the formal parameters. 128 /// args is the list of arguments currently given to the actual function, the last of which needs to be restructured. 129 template< typename Iterator, typename OutIterator > 130 void fixLastArg( Expression * last, Iterator begin, Iterator end, OutIterator out ) { 131 if ( Tuples::isTtype( last->get_result() ) ) { 132 *out++ = last; 133 } else { 134 // safe_dynamic_cast for the assertion 135 safe_dynamic_cast< TupleType * >( last->get_result() ); 136 unsigned idx = 0; 137 for ( ; begin != end; ++begin ) { 138 DeclarationWithType * formal = *begin; 139 Type * formalType = formal->get_type(); 140 matchOneFormal( last, idx, formalType, out ); 141 } 142 delete last; 150 assertf( begin != end, "reached the end of the arguments while structuring" ); 151 *out++ = *begin++; 152 } 153 } 154 155 /// explode assuming simple cases: either type is pure tuple (but not tuple expr) or type is non-tuple. 156 template< typename OutputIterator > 157 void explodeSimple( Expression * expr, OutputIterator out ) { 158 if ( TupleType * tupleType = dynamic_cast< TupleType * > ( expr->get_result() ) ) { 159 // tuple type, recursively index into its components 160 for ( unsigned int i = 0; i < tupleType->size(); i++ ) { 161 explodeSimple( new TupleIndexExpr( expr->clone(), i ), out ); 162 } 163 delete expr; 164 } else { 165 // non-tuple type - output a clone of the expression 166 *out++ = expr; 143 167 } 144 168 } … … 173 197 std::list< DeclarationWithType * >::iterator actualBegin = actualType->get_parameters().begin(); 174 198 std::list< DeclarationWithType * >::iterator actualEnd = actualType->get_parameters().end(); 175 std::list< DeclarationWithType * >::iterator formalBegin = funType->get_parameters().begin(); 176 std::list< DeclarationWithType * >::iterator formalEnd = funType->get_parameters().end(); 177 199 200 std::list< Expression * > args; 178 201 for ( DeclarationWithType* param : thunkFunc->get_functionType()->get_parameters() ) { 179 // walk the parameters to the actual function alongside the parameters to the thunk to find the location where the ttype parameter begins to satisfy parameters in the actual function.202 // name each thunk parameter and explode it - these are then threaded back into the actual function call. 180 203 param->set_name( paramNamer.newName() ); 181 assertf( formalBegin != formalEnd, "Reached end of formal parameters before finding ttype parameter" ); 182 if ( Tuples::isTtype((*formalBegin)->get_type()) ) { 183 fixLastArg( new VariableExpr( param ), actualBegin, actualEnd, back_inserter( appExpr->get_args() ) ); 184 break; 185 } 186 assertf( actualBegin != actualEnd, "reached end of actual function's arguments before finding ttype parameter" ); 187 ++actualBegin; 188 ++formalBegin; 189 190 appExpr->get_args().push_back( new VariableExpr( param ) ); 191 } // for 204 explodeSimple( new VariableExpr( param ), back_inserter( args ) ); 205 } 206 207 // walk parameters to the actual function alongside the exploded thunk parameters and restructure the arguments to match the actual parameters. 208 std::list< Expression * >::iterator argBegin = args.begin(), argEnd = args.end(); 209 for ( ; actualBegin != actualEnd; ++actualBegin ) { 210 structureArg( (*actualBegin)->get_type(), argBegin, argEnd, back_inserter( appExpr->get_args() ) ); 211 } 212 192 213 appExpr->set_env( maybeClone( env ) ); 193 214 if ( inferParams ) { -
src/InitTweak/GenInit.cc
r4da6a6c r2f26687a 218 218 219 219 bool CtorDtor::isManaged( Type * type ) const { 220 // need to clear and reset qualifiers when determining if a type is managed 221 ValueGuard< Type::Qualifiers > qualifiers( type->get_qualifiers() ); 222 type->get_qualifiers() = Type::Qualifiers(); 220 223 if ( TupleType * tupleType = dynamic_cast< TupleType * > ( type ) ) { 221 224 // tuple is also managed if any of its components are managed -
src/Parser/parser.yy
r4da6a6c r2f26687a 412 412 { $$ = new ExpressionNode( build_fieldSel( $1, build_field_name_REALFRACTIONconstant( *$2 ) ) ); } 413 413 | postfix_expression ARROW no_attr_identifier 414 { $$ = new ExpressionNode( build_pfieldSel( $1, build_varref( $3 ) ) ); } 414 { 415 $$ = new ExpressionNode( build_pfieldSel( $1, *$3 == "0" || *$3 == "1" ? build_constantInteger( *$3 ) : build_varref( $3 ) ) ); 416 } 415 417 | postfix_expression ARROW '[' push field_list pop ']' // CFA, tuple field selector 416 418 { $$ = new ExpressionNode( build_pfieldSel( $1, build_tuple( $5 ) ) ); } 419 | postfix_expression ARROW INTEGERconstant // CFA, tuple index 420 { $$ = new ExpressionNode( build_pfieldSel( $1, build_constantInteger( *$3 ) ) ); } 417 421 | postfix_expression ICR 418 422 { $$ = new ExpressionNode( build_unary_ptr( OperKinds::IncrPost, $1 ) ); } -
src/ResolvExpr/Resolver.cc
r4da6a6c r2f26687a 240 240 functionReturn = ResolvExpr::extractResultType( functionDecl->get_functionType() ); 241 241 Parent::visit( functionDecl ); 242 243 // default value expressions have an environment which shouldn't be there and trips up later passes. 244 // xxx - it might be necessary to somehow keep the information from this environment, but I can't currently 245 // see how it's useful. 246 for ( Declaration * d : functionDecl->get_functionType()->get_parameters() ) { 247 if ( ObjectDecl * obj = dynamic_cast< ObjectDecl * >( d ) ) { 248 if ( SingleInit * init = dynamic_cast< SingleInit * >( obj->get_init() ) ) { 249 delete init->get_value()->get_env(); 250 init->get_value()->set_env( nullptr ); 251 } 252 } 253 } 242 254 } 243 255 -
src/SymTab/Autogen.cc
r4da6a6c r2f26687a 151 151 bool hasDynamicLayout( AggrDecl * aggregateDecl ) { 152 152 for ( TypeDecl * param : aggregateDecl->get_parameters() ) { 153 if ( param-> get_kind() == TypeDecl::Any) return true;153 if ( param->isComplete() ) return true; 154 154 } 155 155 return false; -
src/SymTab/Indexer.cc
r4da6a6c r2f26687a 119 119 FunctionDecl * decl; 120 120 bool isUserDefinedFunc; // properties for this particular decl 121 bool isDefaultFunc; 121 bool isDefaultCtor; 122 bool isDtor; 122 123 bool isCopyFunc; 123 124 }; 124 125 // properties for this type 125 bool userDefinedFunc = false; // any user defined function found 126 bool userDefinedDefaultFunc = false; // user defined default ctor found 127 bool userDefinedCopyFunc = false; // user defined copy ctor found 126 bool userDefinedFunc = false; // any user-defined function found 127 bool userDefinedCtor = false; // any user-defined constructor found 128 bool userDefinedDtor = false; // any user-defined destructor found 129 bool userDefinedCopyFunc = false; // user-defined copy ctor found 128 130 std::list< DeclBall > decls; 129 131 … … 132 134 ValueType & operator+=( FunctionDecl * function ) { 133 135 bool isUserDefinedFunc = ! LinkageSpec::isOverridable( function->get_linkage() ); 134 bool isDefaultFunc = function->get_functionType()->get_parameters().size() == 1; 136 bool isDefaultCtor = InitTweak::isDefaultConstructor( function ); 137 bool isDtor = InitTweak::isDestructor( function ); 135 138 bool isCopyFunc = InitTweak::isCopyFunction( function, function->get_name() ); 136 decls.push_back( DeclBall{ function, isUserDefinedFunc, isDefault Func, isCopyFunc } );139 decls.push_back( DeclBall{ function, isUserDefinedFunc, isDefaultCtor, isDtor, isCopyFunc } ); 137 140 userDefinedFunc = userDefinedFunc || isUserDefinedFunc; 138 userDefinedDefaultFunc = userDefinedDefaultFunc || (isUserDefinedFunc && isDefaultFunc); 141 userDefinedCtor = userDefinedCtor || (isUserDefinedFunc && InitTweak::isConstructor( function->get_name() ) ); 142 userDefinedDtor = userDefinedDtor || (isUserDefinedFunc && isDtor); 139 143 userDefinedCopyFunc = userDefinedCopyFunc || (isUserDefinedFunc && isCopyFunc); 140 144 return *this; … … 163 167 // a default ctor, then the generated default ctor should never be seen, likewise for copy ctor 164 168 // and dtor. If the user defines any ctor/dtor, then no generated field ctors should be seen. 169 // If the user defines any ctor then the generated default ctor should not be seen. 165 170 for ( std::pair< const std::string, ValueType > & pair : funcMap ) { 166 171 ValueType & val = pair.second; 167 172 for ( ValueType::DeclBall ball : val.decls ) { 168 if ( ! val.userDefinedFunc || ball.isUserDefinedFunc || (! val.userDefined DefaultFunc && ball.isDefaultFunc) || (! val.userDefinedCopyFunc && ball.isCopyFunc) ) {173 if ( ! val.userDefinedFunc || ball.isUserDefinedFunc || (! val.userDefinedCtor && ball.isDefaultCtor) || (! val.userDefinedCopyFunc && ball.isCopyFunc) || (! val.userDefinedDtor && ball.isDtor) ) { 169 174 // decl conforms to the rules described above, so it should be seen by the requester 170 175 out.push_back( ball.decl ); -
src/SymTab/Validate.cc
r4da6a6c r2f26687a 224 224 HoistStruct::hoistStruct( translationUnit ); 225 225 ReturnTypeFixer::fix( translationUnit ); // must happen before autogen 226 acceptAll( translationUnit, lrt ); // must happen before autogen, because sized flag needs to propagate to generated functions 226 227 autogenerateRoutines( translationUnit ); // moved up, used to be below compoundLiteral - currently needs EnumAndPointerDecayPass 227 228 acceptAll( translationUnit, epc ); 228 acceptAll( translationUnit, lrt );229 229 ReturnChecker::checkFunctionReturns( translationUnit ); 230 230 compoundliteral.mutateDeclarationList( translationUnit ); … … 838 838 assertf( retVals.size() == 0 || retVals.size() == 1, "Function %s has too many return values: %d", functionDecl->get_name().c_str(), retVals.size() ); 839 839 if ( retVals.size() == 1 ) { 840 // ensure all function return values have a name - use the name of the function to disambiguate (this also provides a nice bit of help for debugging) 841 // ensure other return values have a name 840 // ensure all function return values have a name - use the name of the function to disambiguate (this also provides a nice bit of help for debugging). 841 // ensure other return values have a name. 842 842 DeclarationWithType * ret = retVals.front(); 843 843 if ( ret->get_name() == "" ) { -
src/SynTree/TypeDecl.cc
r4da6a6c r2f26687a 25 25 26 26 std::string TypeDecl::typeString() const { 27 static const char *kindNames[] = { "type", "incomplete type", "function type", "tuple type" };28 return kindNames[ kind ];27 static const std::string kindNames[] = { "type", "incomplete type", "function type", "tuple type" }; 28 return (kind != Any && isComplete() ? "sized " : "") + kindNames[ kind ]; 29 29 } 30 30 -
src/tests/.expect/tuplePolymorphism.txt
r4da6a6c r2f26687a 3 3 123 999.123 456 4 4 246 1998.25 912 5 1.21 x 10.21 1111 v 54385938 1111 v 54385938 -
src/tests/memberCtors.c
r4da6a6c r2f26687a 30 30 WrappedInt x, y, z; 31 31 }; 32 33 void ?{}(A * a) { 34 // currently must define default ctor, since there's no "= default" syntax 35 } 32 36 33 37 void ?{}(A * a, int x) { -
src/tests/tuplePolymorphism.c
r4da6a6c r2f26687a 14 14 // 15 15 16 // packed is needed so that structs are not passed with the same alignment as function arguments 17 __attribute__((packed)) struct A { 18 double x; 19 char y; 20 double z; 21 }; 22 23 __attribute__((packed)) struct B { 24 long long x; 25 char y; 26 long long z; 27 }; 28 29 // ensure that f is a viable candidate for g, even though its parameter structure does not exactly match 30 [A] f([A, B] x, B y) { printf("%g %c %g %lld %c %lld %lld %c %lld\n", x.0.[x,y,z], x.1.[x,y,z], y.[x,y,z]); return x.0; } 31 forall(otype T, otype U | { T f(T, U, U); }) 32 void g(T x, U y) { f(x, y, y); } 33 34 // add two triples 16 35 forall(otype T | { T ?+?(T, T); }) 17 36 [T, T, T] ?+?([T, T, T] x, [T, T, T] y) { … … 40 59 [x1, x2, x3] = zzz+zzz; 41 60 printf("%d %g %d\n", x1, x2, x3); 61 62 // ensure non-matching assertions are specialized correctly 63 g((A){ 1.21, 'x', 10.21}, (B){ 1111LL, 'v', 54385938LL }); 42 64 } 43 65
Note: See TracChangeset
for help on using the changeset viewer.