Changeset b9fe89b for src


Ignore:
Timestamp:
Jun 5, 2023, 1:29:55 PM (13 months ago)
Author:
Michael Brooks <mlbrooks@…>
Branches:
ast-experimental, master
Children:
134e6d9
Parents:
84334d0
Message:

Make the symbol table's error-checking times explicit.

Previously, error checking happened on all WithSymbolTable? uses. Error checking means having a symbol-table add operation potentially cause a user-visible error report. Now, this only happens on the resolver pass's symbol table, while other passes' run in an "assert no errors can happen" mode.

An "ignore errors for now" mode is implemented too, which will be used in upcoming commits, for pre-resolver passes that use the symbol table.

Location:
src
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • src/AST/Pass.hpp

    r84334d0 rb9fe89b  
    414414};
    415415
    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 &)
    417426struct 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};
     431template <ast::SymbolTable::ErrorDetection errorMode>
     432struct WithSymbolTableX : WithSymbolTable {
     433        WithSymbolTableX() : WithSymbolTable(errorMode) {}
    419434};
    420435
  • src/AST/SymbolTable.cpp

    r84334d0 rb9fe89b  
    8888}
    8989
    90 SymbolTable::SymbolTable()
     90SymbolTable::SymbolTable( ErrorDetection errorMode )
    9191: idTable(), typeTable(), structTable(), enumTable(), unionTable(), traitTable(),
    92   prevScope(), scope( 0 ), repScope( 0 ) { ++*stats().count; }
     92  prevScope(), scope( 0 ), repScope( 0 ), errorMode(errorMode) { ++*stats().count; }
    9393
    9494SymbolTable::~SymbolTable() { stats().size->push( idTable ? idTable->size() : 0 ); }
     95
     96void SymbolTable::OnFindError( CodeLocation location, std::string error ) const {
     97        assertf( errorMode != AssertClean, "Name collision/redefinition, found during a compilation phase where none should be possible.  Detail: %s", error.c_str() );
     98        if (errorMode == ValidateOnAdd) {
     99                SemanticError(location, error);
     100        }
     101        assertf( errorMode == IgnoreErrors, "Unrecognized symbol-table error mode %d", errorMode );
     102}
    95103
    96104void SymbolTable::enterScope() {
     
    269277}
    270278
    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
     279bool SymbolTable::addedTypeConflicts(
     280                const NamedTypeDecl * existing, const NamedTypeDecl * added ) const {
     281        if ( existing->base == nullptr ) {
     282                return false;
     283        } else if ( added->base == nullptr ) {
    286284                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         }
     285        } else {
     286                // typedef redeclarations are errors only if types are different
     287                if ( ! ResolvExpr::typesCompatible( existing->base, added->base ) ) {
     288                        OnFindError( added->location, "redeclaration of " + added->name );
     289                }
     290        }
     291        // does not need to be added to the table if both existing and added have a base that are
     292        // the same
     293        return true;
     294}
     295
     296bool SymbolTable::addedDeclConflicts(
     297                const AggregateDecl * existing, const AggregateDecl * added ) const {
     298        if ( ! existing->body ) {
     299                return false;
     300        } else if ( added->body ) {
     301                OnFindError( added, "redeclaration of " );
     302        }
     303        return true;
    298304}
    299305
     
    648654                if ( deleter && ! existing.deleter ) {
    649655                        if ( handleConflicts.mode == OnConflict::Error ) {
    650                                 SemanticError( added, "deletion of defined identifier " );
     656                                OnFindError( added, "deletion of defined identifier " );
    651657                        }
    652658                        return true;
    653659                } else if ( ! deleter && existing.deleter ) {
    654660                        if ( handleConflicts.mode == OnConflict::Error ) {
    655                                 SemanticError( added, "definition of deleted identifier " );
     661                                OnFindError( added, "definition of deleted identifier " );
    656662                        }
    657663                        return true;
     
    661667                if ( isDefinition( added ) && isDefinition( existing.id ) ) {
    662668                        if ( handleConflicts.mode == OnConflict::Error ) {
    663                                 SemanticError( added,
     669                                OnFindError( added,
    664670                                        isFunction( added ) ?
    665671                                                "duplicate function definition for " :
     
    670676        } else {
    671677                if ( handleConflicts.mode == OnConflict::Error ) {
    672                         SemanticError( added, "duplicate definition for " );
     678                        OnFindError( added, "duplicate definition for " );
    673679                }
    674680                return true;
     
    722728                // Check that a Cforall declaration doesn't override any C declaration
    723729                if ( hasCompatibleCDecl( name, mangleName ) ) {
    724                         SemanticError( decl, "Cforall declaration hides C function " );
     730                        OnFindError( decl, "Cforall declaration hides C function " );
    725731                }
    726732        } else {
     
    728734                // type-compatibility, which it may not be.
    729735                if ( hasIncompatibleCDecl( name, mangleName ) ) {
    730                         SemanticError( decl, "conflicting overload of C function " );
     736                        OnFindError( decl, "conflicting overload of C function " );
    731737                }
    732738        }
  • src/AST/SymbolTable.hpp

    r84334d0 rb9fe89b  
    9393
    9494public:
    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) {}
    96109        ~SymbolTable();
     110
     111        ErrorDetection getErrorMode() const {
     112                return errorMode;
     113        }
    97114
    98115        // when using an indexer manually (e.g., within a mutator traversal), it is necessary to
     
    158175
    159176private:
     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
    160189        /// Ensures that a proper backtracking scope exists before a mutation
    161190        void lazyInitScope();
     
    168197        bool removeSpecialOverrides( IdData & decl, MangleTable::Ptr & mangleTable );
    169198
    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.
    171209        struct OnConflict {
    172210                enum {
    173                         Error,  ///< Throw a semantic error
     211                        Error,  ///< Follow the current pass's ErrorDetection mode (may throw a semantic error)
    174212                        Delete  ///< Delete the earlier version with the delete statement
    175213                } mode;
     
    191229                const Decl * deleter );
    192230
     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
    193237        /// common code for addId, addDeletedId, etc.
    194238        void addIdCommon(
     
    213257}
    214258
     259
    215260// Local Variables: //
    216261// tab-width: 4 //
  • src/ResolvExpr/Resolver.cc

    r84334d0 rb9fe89b  
    12611261                static size_t traceId;
    12621262                Resolver_new( const ast::TranslationGlobal & global ) :
     1263                        ast::WithSymbolTable(ast::SymbolTable::ErrorDetection::ValidateOnAdd),
    12631264                        context{ symtab, global } {}
    12641265                Resolver_new( const ResolveContext & context ) :
Note: See TracChangeset for help on using the changeset viewer.