Changeset 48ec19a for src


Ignore:
Timestamp:
Jun 26, 2023, 10:51:47 AM (2 years ago)
Author:
caparson <caparson@…>
Branches:
master
Children:
917e1fd
Parents:
adc73a5 (diff), 1fbf481 (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.
Message:

Merge branch 'master' of plg.uwaterloo.ca:software/cfa/cfa-cc

Location:
src
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • src/AST/Decl.cpp

    radc73a5 r48ec19a  
    115115        static_assert( sizeof(kindNames) / sizeof(kindNames[0]) == TypeDecl::NUMBER_OF_KINDS, "typeString: kindNames is out of sync." );
    116116        assertf( kind < TypeDecl::NUMBER_OF_KINDS, "TypeDecl kind is out of bounds." );
    117         return sized ? kindNames[ kind ] : &kindNames[ kind ][ sizeof("sized") ]; // sizeof includes '\0'
     117        // sizeof("sized") includes '\0' and gives the offset to remove "sized ".
     118        return sized ? kindNames[ kind ] : &kindNames[ kind ][ sizeof("sized") ];
    118119}
    119120
  • src/InitTweak/GenInit.cc

    radc73a5 r48ec19a  
    300300
    301301#       warning Remove the _New suffix after the conversion is complete.
     302
     303        // Outer pass finds declarations, for their type could wrap a type that needs hoisting
    302304        struct HoistArrayDimension_NoResolve_New final :
    303305                        public ast::WithDeclsToAdd<>, public ast::WithShortCircuiting,
    304306                        public ast::WithGuards, public ast::WithConstTranslationUnit,
    305                         public ast::WithVisitorRef<HoistArrayDimension_NoResolve_New> {
    306                 void previsit( const ast::ObjectDecl * decl );
    307                 const ast::DeclWithType * postvisit( const ast::ObjectDecl * decl );
    308                 // Do not look for objects inside there declarations (and type).
    309                 void previsit( const ast::AggregateDecl * ) { visit_children = false; }
    310                 void previsit( const ast::NamedTypeDecl * ) { visit_children = false; }
    311                 void previsit( const ast::FunctionType * ) { visit_children = false; }
    312 
    313                 const ast::Type * hoist( const ast::Type * type );
     307                        public ast::WithVisitorRef<HoistArrayDimension_NoResolve_New>,
     308                        public ast::WithSymbolTableX<ast::SymbolTable::ErrorDetection::IgnoreErrors> {
     309
     310                // Inner pass looks within a type, for a part that depends on an expression
     311                struct HoistDimsFromTypes final :
     312                                public ast::WithShortCircuiting, public ast::WithGuards {
     313
     314                        HoistArrayDimension_NoResolve_New * outer;
     315                        HoistDimsFromTypes( HoistArrayDimension_NoResolve_New * outer ) : outer(outer) {}
     316
     317                        // Only intended for visiting through types.
     318                        // Tolerate, and short-circuit at, the dimension expression of an array type.
     319                        //    (We'll operate on the dimension expression of an array type directly
     320                        //    from the parent type, not by visiting through it)
     321                        // Look inside type exprs.
     322                        void previsit( const ast::Node * ) {
     323                                assert( false && "unsupported node type" );
     324                        };
     325                        const ast::Expr * allowedExpr = nullptr;
     326                        void previsit( const ast::Type * ) {
     327                                GuardValue( allowedExpr ) = nullptr;
     328                        }
     329                        void previsit( const ast::ArrayType * t ) {
     330                                GuardValue( allowedExpr ) = t->dimension.get();
     331                        }
     332                        void previsit( const ast::PointerType * t ) {
     333                                GuardValue( allowedExpr ) = t->dimension.get();
     334                        }
     335                        void previsit( const ast::TypeofType * t ) {
     336                                GuardValue( allowedExpr ) = t->expr.get();
     337                        }
     338                        void previsit( const ast::Expr * e ) {
     339                                assert( e == allowedExpr &&
     340                                    "only expecting to visit exprs that are dimension exprs or typeof(-) inner exprs" );
     341
     342                                // Skip the tolerated expressions
     343                                visit_children = false;
     344                        }
     345                        void previsit( const ast::TypeExpr * ) {}
     346
     347                        const ast::Type * postvisit(
     348                                        const ast::ArrayType * arrayType ) {
     349                                static UniqueName dimensionName( "_array_dim" );
     350
     351                                if ( nullptr == arrayType->dimension ) {  // if no dimension is given, don't presume to invent one
     352                                        return arrayType;
     353                                }
     354
     355                                // find size_t; use it as the type for a dim expr
     356                                ast::ptr<ast::Type> dimType = outer->transUnit().global.sizeType;
     357                                assert( dimType );
     358                                add_qualifiers( dimType, ast::CV::Qualifiers( ast::CV::Const ) );
     359
     360                                // Special-case handling: leave the user's dimension expression alone
     361                                // - requires the user to have followed a careful convention
     362                                // - may apply to extremely simple applications, but only as windfall
     363                                // - users of advanced applications will be following the convention on purpose
     364                                // - CFA maintainers must protect the criteria against leaving too much alone
     365
     366                                // Actual leave-alone cases following are conservative approximations of "cannot vary"
     367
     368                                // Leave alone: literals and enum constants
     369                                if ( dynamic_cast< const ast::ConstantExpr * >( arrayType->dimension.get() ) ) {
     370                                        return arrayType;
     371                                }
     372
     373                                // Leave alone: direct use of an object declared to be const
     374                                const ast::NameExpr * dimn = dynamic_cast< const ast::NameExpr * >( arrayType->dimension.get() );
     375                                if ( dimn ) {
     376                                        std::vector<ast::SymbolTable::IdData> dimnDefs = outer->symtab.lookupId( dimn->name );
     377                                        if ( dimnDefs.size() == 1 ) {
     378                                                const ast::DeclWithType * dimnDef = dimnDefs[0].id.get();
     379                                                assert( dimnDef && "symbol table binds a name to nothing" );
     380                                                const ast::ObjectDecl * dimOb = dynamic_cast< const ast::ObjectDecl * >( dimnDef );
     381                                                if( dimOb ) {
     382                                                        const ast::Type * dimTy = dimOb->type.get();
     383                                                        assert( dimTy && "object declaration bearing no type" );
     384                                                        // must not hoist some: size_t
     385                                                        // must hoist all: pointers and references
     386                                                        // the analysis is conservative; BasicType is a simple approximation
     387                                                        if ( dynamic_cast< const ast::BasicType * >( dimTy ) ||
     388                                                             dynamic_cast< const ast::SueInstType<ast::EnumDecl> * >( dimTy ) ) {
     389                                                                if ( dimTy->is_const() ) {
     390                                                                        // The dimension is certainly re-evaluable, giving the same answer each time.
     391                                                                        // Our user might be hoping to write the array type in multiple places, having them unify.
     392                                                                        // Leave the type alone.
     393
     394                                                                        // We believe the new criterion leaves less alone than the old criterion.
     395                                                                        // Thus, the old criterion should have left the current case alone.
     396                                                                        // Catch cases that weren't thought through.
     397                                                                        assert( !Tuples::maybeImpure( arrayType->dimension ) );
     398
     399                                                                        return arrayType;
     400                                                                }
     401                                                        };
     402                                                }
     403                                        }
     404                                }
     405
     406                                // Leave alone: any sizeof expression (answer cannot vary during current lexical scope)
     407                                const ast::SizeofExpr * sz = dynamic_cast< const ast::SizeofExpr * >( arrayType->dimension.get() );
     408                                if ( sz ) {
     409                                        return arrayType;
     410                                }
     411
     412                                // General-case handling: change the array-type's dim expr (hoist the user-given content out of the type)
     413                                // - always safe
     414                                // - user-unnoticeable in common applications (benign noise in -CFA output)
     415                                // - may annoy a responsible user of advanced applications (but they can work around)
     416                                // - protects against misusing advanced features
     417                                //
     418                                // The hoist, by example, is:
     419                                // FROM USER:  float a[ rand() ];
     420                                // TO GCC:     const size_t __len_of_a = rand(); float a[ __len_of_a ];
     421
     422                                ast::ObjectDecl * arrayDimension = new ast::ObjectDecl(
     423                                        arrayType->dimension->location,
     424                                        dimensionName.newName(),
     425                                        dimType,
     426                                        new ast::SingleInit(
     427                                                arrayType->dimension->location,
     428                                                arrayType->dimension
     429                                        )
     430                                );
     431
     432                                ast::ArrayType * mutType = ast::mutate( arrayType );
     433                                mutType->dimension = new ast::VariableExpr(
     434                                                arrayDimension->location, arrayDimension );
     435                                outer->declsToAddBefore.push_back( arrayDimension );
     436
     437                                return mutType;
     438                        }  // postvisit( const ast::ArrayType * )
     439                }; // struct HoistDimsFromTypes
    314440
    315441                ast::Storage::Classes storageClasses;
     442                void previsit(
     443                                const ast::ObjectDecl * decl ) {
     444                        GuardValue( storageClasses ) = decl->storage;
     445                }
     446
     447                const ast::DeclWithType * postvisit(
     448                                const ast::ObjectDecl * objectDecl ) {
     449
     450                        if ( !isInFunction() || storageClasses.is_static ) {
     451                                return objectDecl;
     452                        }
     453
     454                        const ast::Type * mid = objectDecl->type;
     455
     456                        ast::Pass<HoistDimsFromTypes> hoist{this};
     457                        const ast::Type * result = mid->accept( hoist );
     458
     459                        return mutate_field( objectDecl, &ast::ObjectDecl::type, result );
     460                }
    316461        };
    317462
    318         void HoistArrayDimension_NoResolve_New::previsit(
    319                         const ast::ObjectDecl * decl ) {
    320                 GuardValue( storageClasses ) = decl->storage;
    321         }
    322 
    323         const ast::DeclWithType * HoistArrayDimension_NoResolve_New::postvisit(
    324                         const ast::ObjectDecl * objectDecl ) {
    325                 return mutate_field( objectDecl, &ast::ObjectDecl::type,
    326                                 hoist( objectDecl->type ) );
    327         }
    328 
    329         const ast::Type * HoistArrayDimension_NoResolve_New::hoist(
    330                         const ast::Type * type ) {
    331                 static UniqueName dimensionName( "_array_dim" );
    332 
    333                 if ( !isInFunction() || storageClasses.is_static ) {
    334                         return type;
    335                 }
    336 
    337                 if ( auto arrayType = dynamic_cast< const ast::ArrayType * >( type ) ) {
    338                         if ( nullptr == arrayType->dimension ) {
    339                                 return type;
    340                         }
    341 
    342                         if ( !Tuples::maybeImpure( arrayType->dimension ) ) {
    343                                 return type;
    344                         }
    345 
    346                         ast::ptr<ast::Type> dimType = transUnit().global.sizeType;
    347                         assert( dimType );
    348                         add_qualifiers( dimType, ast::CV::Qualifiers( ast::CV::Const ) );
    349 
    350                         ast::ObjectDecl * arrayDimension = new ast::ObjectDecl(
    351                                 arrayType->dimension->location,
    352                                 dimensionName.newName(),
    353                                 dimType,
    354                                 new ast::SingleInit(
    355                                         arrayType->dimension->location,
    356                                         arrayType->dimension
    357                                 )
    358                         );
    359 
    360                         ast::ArrayType * mutType = ast::mutate( arrayType );
    361                         mutType->dimension = new ast::VariableExpr(
    362                                         arrayDimension->location, arrayDimension );
    363                         declsToAddBefore.push_back( arrayDimension );
    364 
    365                         mutType->base = hoist( mutType->base );
    366                         return mutType;
    367                 }
    368                 return type;
    369         }
     463
     464
    370465
    371466        struct ReturnFixer_New final :
  • src/ResolvExpr/ResolveTypeof.h

    radc73a5 r48ec19a  
    3030        Type *resolveTypeof( Type*, const SymTab::Indexer &indexer );
    3131        const ast::Type * resolveTypeof( const ast::Type *, const ResolveContext & );
     32        const ast::Type * fixArrayType( const ast::Type *, const ResolveContext & );
    3233        const ast::ObjectDecl * fixObjectType( const ast::ObjectDecl * decl , const ResolveContext & );
    3334} // namespace ResolvExpr
  • src/ResolvExpr/Unify.cc

    radc73a5 r48ec19a  
    3232#include "AST/Type.hpp"
    3333#include "AST/TypeEnvironment.hpp"
     34#include "Common/Eval.h"            // for eval
    3435#include "Common/PassVisitor.h"     // for PassVisitor
    3536#include "CommonType.hpp"           // for commonType
     
    779780        }
    780781
     782        // Unification of Expressions
     783        //
     784        // Boolean outcome (obvious):  Are they basically spelled the same?
     785        // Side effect of binding variables (subtle):  if `sizeof(int)` ===_expr `sizeof(T)` then `int` ===_ty `T`
     786        //
     787        // Context:  if `float[VAREXPR1]` ===_ty `float[VAREXPR2]` then `VAREXPR1` ===_expr `VAREXPR2`
     788        // where the VAREXPR are meant as notational metavariables representing the fact that unification always
     789        // sees distinct ast::VariableExpr objects at these positions
     790
     791        static bool unify( const ast::Expr * e1, const ast::Expr * e2, ast::TypeEnvironment & env,
     792                ast::AssertionSet & need, ast::AssertionSet & have, const ast::OpenVarSet & open,
     793                WidenMode widen );
     794
     795        class UnifyExpr final : public ast::WithShortCircuiting {
     796                const ast::Expr * e2;
     797                ast::TypeEnvironment & tenv;
     798                ast::AssertionSet & need;
     799                ast::AssertionSet & have;
     800                const ast::OpenVarSet & open;
     801                WidenMode widen;
     802        public:
     803                bool result;
     804
     805        private:
     806
     807                void tryMatchOnStaticValue( const ast::Expr * e1 ) {
     808                        Evaluation r1 = eval(e1);
     809                        Evaluation r2 = eval(e2);
     810
     811                        if ( ! r1.hasKnownValue ) return;
     812                        if ( ! r2.hasKnownValue ) return;
     813
     814                        if (r1.knownValue != r2.knownValue) return;
     815
     816                        visit_children = false;
     817                        result = true;
     818                }
     819
     820        public:
     821
     822                void previsit( const ast::Node * ) { assert(false); }
     823
     824                void previsit( const ast::Expr * e1 ) {
     825                        tryMatchOnStaticValue( e1 );
     826                        visit_children = false;
     827                }
     828
     829                void previsit( const ast::CastExpr * e1 ) {
     830                        tryMatchOnStaticValue( e1 );
     831
     832                        if (result) {
     833                                assert (visit_children == false);
     834                        } else {
     835                                assert (visit_children == true);
     836                                visit_children = false;
     837
     838                                auto e2c = dynamic_cast< const ast::CastExpr * >( e2 );
     839                                if ( ! e2c ) return;
     840
     841                                // inspect casts' target types
     842                                if ( ! unifyExact(
     843                                        e1->result, e2c->result, tenv, need, have, open, widen ) ) return;
     844
     845                                // inspect casts' inner expressions
     846                                result = unify( e1->arg, e2c->arg, tenv, need, have, open, widen );
     847                        }
     848                }
     849
     850                void previsit( const ast::VariableExpr * e1 ) {
     851                        tryMatchOnStaticValue( e1 );
     852
     853                        if (result) {
     854                                assert (visit_children == false);
     855                        } else {
     856                                assert (visit_children == true);
     857                                visit_children = false;
     858
     859                                auto e2v = dynamic_cast< const ast::VariableExpr * >( e2 );
     860                                if ( ! e2v ) return;
     861
     862                                assert(e1->var);
     863                                assert(e2v->var);
     864
     865                                // conservative: variable exprs match if their declarations are represented by the same C++ AST object
     866                                result = (e1->var == e2v->var);
     867                        }
     868                }
     869
     870                void previsit( const ast::SizeofExpr * e1 ) {
     871                        tryMatchOnStaticValue( e1 );
     872
     873                        if (result) {
     874                                assert (visit_children == false);
     875                        } else {
     876                                assert (visit_children == true);
     877                                visit_children = false;
     878
     879                                auto e2so = dynamic_cast< const ast::SizeofExpr * >( e2 );
     880                                if ( ! e2so ) return;
     881
     882                                assert((e1->type != nullptr) ^ (e1->expr != nullptr));
     883                                assert((e2so->type != nullptr) ^ (e2so->expr != nullptr));
     884                                if ( ! (e1->type && e2so->type) )  return;
     885
     886                                // expression unification calls type unification (mutual recursion)
     887                                result = unifyExact( e1->type, e2so->type, tenv, need, have, open, widen );
     888                        }
     889                }
     890
     891                UnifyExpr( const ast::Expr * e2, ast::TypeEnvironment & env, ast::AssertionSet & need,
     892                        ast::AssertionSet & have, const ast::OpenVarSet & open, WidenMode widen )
     893                : e2( e2 ), tenv(env), need(need), have(have), open(open), widen(widen), result(false) {}
     894        };
     895
     896        static bool unify( const ast::Expr * e1, const ast::Expr * e2, ast::TypeEnvironment & env,
     897                ast::AssertionSet & need, ast::AssertionSet & have, const ast::OpenVarSet & open,
     898                WidenMode widen ) {
     899                assert( e1 && e2 );
     900                return ast::Pass<UnifyExpr>::read( e1, e2, env, need, have, open, widen );
     901        }
     902
    781903        class Unify_new final : public ast::WithShortCircuiting {
    782904                const ast::Type * type2;
     
    820942                        if ( ! array2 ) return;
    821943
    822                         // to unify, array types must both be VLA or both not VLA and both must have a
    823                         // dimension expression or not have a dimension
    824944                        if ( array->isVarLen != array2->isVarLen ) return;
    825                         if ( ! array->isVarLen && ! array2->isVarLen
    826                                         && array->dimension && array2->dimension ) {
    827                                 auto ce1 = array->dimension.as< ast::ConstantExpr >();
    828                                 auto ce2 = array2->dimension.as< ast::ConstantExpr >();
    829 
    830                                 // see C11 Reference Manual 6.7.6.2.6
    831                                 // two array types with size specifiers that are integer constant expressions are
    832                                 // compatible if both size specifiers have the same constant value
    833                                 if ( ce1 && ce2 && ce1->intValue() != ce2->intValue() ) return;
     945                        if ( (array->dimension != nullptr) != (array2->dimension != nullptr) ) return;
     946
     947                        if ( array->dimension ) {
     948                                assert( array2->dimension );
     949                                // type unification calls expression unification (mutual recursion)
     950                                if ( ! unify(array->dimension, array2->dimension,
     951                                    tenv, need, have, open, widen) ) return;
    834952                        }
    835953
  • src/Validate/GenericParameter.cpp

    radc73a5 r48ec19a  
    1616#include "GenericParameter.hpp"
    1717
    18 #include "AST/Copy.hpp"
    1918#include "AST/Decl.hpp"
    2019#include "AST/Expr.hpp"
     
    120119}
    121120
    122 struct ValidateGenericParamsCore : public ast::WithCodeLocation {
     121bool isSizedPolymorphic( const ast::AggregateDecl * decl ) {
     122        for ( const auto & param : decl->params ) {
     123                if ( param->sized ) return true;
     124        }
     125        return false;
     126}
     127
     128struct ValidateGenericParamsCore :
     129                public ast::WithCodeLocation, public ast::WithGuards {
     130        // Generic parameter filling and checks:
    123131        const ast::StructInstType * previsit( const ast::StructInstType * type ) {
    124132                assert( location );
     
    130138                return validateGeneric( *location, type );
    131139        }
     140
     141        // Check parameter and bitfield combinations:
     142        bool insideSized = false;
     143        void previsit( const ast::StructDecl * decl ) {
     144                if ( isSizedPolymorphic( decl ) && !insideSized ) {
     145                        GuardValue( insideSized ) = true;
     146                }
     147        }
     148
     149        void previsit( const ast::UnionDecl * decl ) {
     150                if ( isSizedPolymorphic( decl ) && !insideSized ) {
     151                        GuardValue( insideSized ) = true;
     152                }
     153        }
     154
     155        void previsit( const ast::ObjectDecl * decl ) {
     156                if ( insideSized && decl->bitfieldWidth ) {
     157                        SemanticError( decl->location, decl,
     158                                "Cannot have bitfields inside a sized polymorphic structure." );
     159                }
     160        }
    132161};
    133162
     
    135164
    136165struct TranslateDimensionCore :
    137                 public WithNoIdSymbolTable, public ast::WithGuards {
     166                public WithNoIdSymbolTable, public ast::WithGuards,
     167                public ast::WithVisitorRef<TranslateDimensionCore> {
    138168
    139169        // SUIT: Struct- or Union- InstType
     
    160190
    161191        const ast::TypeDecl * postvisit( const ast::TypeDecl * decl );
     192        const ast::Type * postvisit( const ast::FunctionType * type );
     193        const ast::Type * postvisit( const ast::TypeInstType * type );
     194
    162195        const ast::Expr * postvisit( const ast::DimensionExpr * expr );
    163196        const ast::Expr * postvisit( const ast::Expr * expr );
     
    165198};
    166199
     200// Declaration of type variable: forall( [N] )  ->  forall( N & | sized( N ) )
    167201const ast::TypeDecl * TranslateDimensionCore::postvisit(
    168202                const ast::TypeDecl * decl ) {
     
    176210        }
    177211        return decl;
     212}
     213
     214// Makes postvisit( TypeInstType ) get called on the entries of the function declaration's type's forall list.
     215// Pass.impl.hpp's visit( FunctionType ) does not consider the forall entries to be child nodes.
     216// Workaround is: during the current TranslateDimension pass, manually visit down there.
     217const ast::Type * TranslateDimensionCore::postvisit(
     218                const ast::FunctionType * type ) {
     219        visitor->maybe_accept( type, &ast::FunctionType::forall );
     220        return type;
     221}
     222
     223// Use of type variable, assuming `forall( [N] )` in scope:  void (*)( foo( /*dimension*/ N ) & )  ->  void (*)( foo( /*dtype*/ N ) & )
     224const ast::Type * TranslateDimensionCore::postvisit(
     225                const ast::TypeInstType * type ) {
     226        if ( type->kind == ast::TypeDecl::Dimension ) {
     227                auto mutType = ast::mutate( type );
     228                mutType->kind = ast::TypeDecl::Dtype;
     229                return mutType;
     230        }
     231        return type;
    178232}
    179233
  • src/Validate/LinkReferenceToTypes.cpp

    radc73a5 r48ec19a  
    8484                // Just linking in the node.
    8585                auto mut = ast::mutate( type );
    86                 mut->base = const_cast<ast::EnumDecl *>( decl );
     86                mut->base = decl;
    8787                type = mut;
    8888        }
     
    101101                // Just linking in the node.
    102102                auto mut = ast::mutate( type );
    103                 mut->base = const_cast<ast::StructDecl *>( decl );
     103                mut->base = decl;
    104104                type = mut;
    105105        }
     
    118118                // Just linking in the node.
    119119                auto mut = ast::mutate( type );
    120                 mut->base = const_cast<ast::UnionDecl *>( decl );
     120                mut->base = decl;
    121121                type = mut;
    122122        }
     
    141141
    142142        // Just linking in the node.
    143         mut->base = const_cast<ast::TraitDecl *>( decl );
     143        mut->base = decl;
    144144
    145145        // Need to carry over the 'sized' status of each decl in the instance.
     
    203203        }
    204204
    205         // The following section
    206 
    207205        ForwardEnumsType::iterator fwds = forwardEnums.find( decl->name );
    208206        if ( fwds != forwardEnums.end() ) {
     
    266264
    267265ast::TraitDecl const * LinkTypesCore::postvisit( ast::TraitDecl const * decl ) {
    268         auto mut = ast::mutate( decl );
    269         if ( mut->name == "sized" ) {
    270                 // "sized" is a special trait - flick the sized status on for the type variable.
    271                 assertf( mut->params.size() == 1, "Built-in trait 'sized' has incorrect number of parameters: %zd", decl->params.size() );
    272                 ast::TypeDecl * td = mut->params.front().get_and_mutate();
    273                 td->sized = true;
    274         }
    275 
    276266        // There is some overlap with code from decayForallPointers,
    277267        // perhaps reorganization or shared helper functions are called for.
    278268        // Move assertions from type parameters into the body of the trait.
     269        auto mut = ast::mutate( decl );
    279270        for ( ast::ptr<ast::TypeDecl> const & td : decl->params ) {
    280271                auto expanded = expandAssertions( td->assertions );
Note: See TracChangeset for help on using the changeset viewer.