source: src/AST/SymbolTable.cpp @ a0bd9a2

Last change on this file since a0bd9a2 was b9fe89b, checked in by Michael Brooks <mlbrooks@…>, 17 months ago

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.

  • Property mode set to 100644
File size: 28.4 KB
Line 
1//
2// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
3//
4// The contents of this file are covered under the licence agreement in the
5// file "LICENCE" distributed with Cforall.
6//
7// SymbolTable.cpp --
8//
9// Author           : Aaron B. Moss
10// Created On       : Wed May 29 11:00:00 2019
11// Last Modified By : Aaron B. Moss
12// Last Modified On : Wed May 29 11:00:00 2019
13// Update Count     : 1
14//
15
16#include "SymbolTable.hpp"
17
18#include <cassert>
19
20#include "Copy.hpp"
21#include "Decl.hpp"
22#include "Expr.hpp"
23#include "Inspect.hpp"
24#include "Type.hpp"
25#include "CodeGen/OperatorTable.h"         // for isCtorDtorAssign
26#include "Common/SemanticError.h"
27#include "Common/Stats/Counter.h"
28#include "GenPoly/GenPoly.h"
29#include "InitTweak/InitTweak.h"
30#include "ResolvExpr/Cost.h"
31#include "ResolvExpr/CandidateFinder.hpp"  // for referenceToRvalueConversion
32#include "ResolvExpr/Unify.h"
33#include "SymTab/Mangler.h"
34
35namespace ast {
36
37// Statistics block
38namespace {
39        static inline auto stats() {
40                using namespace Stats::Counters;
41                static auto group   = build<CounterGroup>("Indexers");
42                static struct {
43                        SimpleCounter * count;
44                        AverageCounter<double> * size;
45                        SimpleCounter * new_scopes;
46                        SimpleCounter * lazy_scopes;
47                        AverageCounter<double> * avg_scope_depth;
48                        MaxCounter<size_t> * max_scope_depth;
49                        SimpleCounter * add_calls;
50                        SimpleCounter * lookup_calls;
51                        SimpleCounter * map_lookups;
52                        SimpleCounter * map_mutations;
53                } ret = {
54                        .count   = build<SimpleCounter>("Count", group),
55                        .size    = build<AverageCounter<double>>("Average Size", group),
56                        .new_scopes = build<SimpleCounter>("Scopes", group),
57                        .lazy_scopes = build<SimpleCounter>("Lazy Scopes", group),
58                        .avg_scope_depth = build<AverageCounter<double>>("Average Scope", group),
59                        .max_scope_depth = build<MaxCounter<size_t>>("Max Scope", group),
60                        .add_calls = build<SimpleCounter>("Add Calls", group),
61                        .lookup_calls = build<SimpleCounter>("Lookup Calls", group),
62                        .map_lookups = build<SimpleCounter>("Map Lookups", group),
63                        .map_mutations = build<SimpleCounter>("Map Mutations", group)
64                };
65                return ret;
66        }
67}
68
69Expr * SymbolTable::IdData::combine( const CodeLocation & loc, ResolvExpr::Cost & cost ) const {
70        Expr * ret;
71        if ( baseExpr ) {
72                if (baseExpr->env) {
73                        Expr * base = deepCopy(baseExpr);
74                        const TypeSubstitution * subs = baseExpr->env;
75                        base->env = nullptr;
76                        ret = new MemberExpr{loc, id, referenceToRvalueConversion( base, cost )};
77                        ret->env = subs;
78                }
79                else {
80                        ret = new MemberExpr{ loc, id, referenceToRvalueConversion( baseExpr, cost ) };
81                }
82        }
83        else {
84                ret = new VariableExpr{ loc, id };
85        }
86        if ( deleter ) { ret = new DeletedExpr{ loc, ret, deleter }; }
87        return ret;
88}
89
90SymbolTable::SymbolTable( ErrorDetection errorMode )
91: idTable(), typeTable(), structTable(), enumTable(), unionTable(), traitTable(),
92  prevScope(), scope( 0 ), repScope( 0 ), errorMode(errorMode) { ++*stats().count; }
93
94SymbolTable::~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}
103
104void SymbolTable::enterScope() {
105        ++scope;
106
107        ++*stats().new_scopes;
108        stats().avg_scope_depth->push( scope );
109        stats().max_scope_depth->push( scope );
110}
111
112void SymbolTable::leaveScope() {
113        if ( repScope == scope ) {
114                Ptr prev = prevScope;           // make sure prevScope stays live
115                *this = std::move(*prevScope);  // replace with previous scope
116        }
117
118        --scope;
119}
120
121SymbolTable::SpecialFunctionKind SymbolTable::getSpecialFunctionKind(const std::string & name) {
122        if (name == "?{}") return CTOR;
123        if (name == "^?{}") return DTOR;
124        if (name == "?=?") return ASSIGN;
125        return NUMBER_OF_KINDS;
126}
127
128std::vector<SymbolTable::IdData> SymbolTable::lookupId( const std::string &id ) const {
129        static Stats::Counters::CounterGroup * name_lookup_stats = Stats::Counters::build<Stats::Counters::CounterGroup>("Name Lookup Stats");
130        static std::map<std::string, Stats::Counters::SimpleCounter *> lookups_by_name;
131        static std::map<std::string, Stats::Counters::SimpleCounter *> candidates_by_name;
132
133        SpecialFunctionKind kind = getSpecialFunctionKind(id);
134        if (kind != NUMBER_OF_KINDS) return specialLookupId(kind);
135
136        ++*stats().lookup_calls;
137        if ( ! idTable ) return {};
138
139        ++*stats().map_lookups;
140        auto decls = idTable->find( id );
141        if ( decls == idTable->end() ) return {};
142
143        std::vector<IdData> out;
144        for ( auto decl : *(decls->second) ) {
145                out.push_back( decl.second );
146        }
147
148        if (Stats::Counters::enabled) {
149                if (! lookups_by_name.count(id)) {
150                        // leaks some strings, but it is because Counters do not hold them
151                        auto lookupCounterName = new std::string(id + "%count");
152                        auto candidatesCounterName = new std::string(id + "%candidate");
153                        lookups_by_name.emplace(id, new Stats::Counters::SimpleCounter(lookupCounterName->c_str(), name_lookup_stats));
154                        candidates_by_name.emplace(id, new Stats::Counters::SimpleCounter(candidatesCounterName->c_str(), name_lookup_stats));
155                }
156                (*lookups_by_name[id]) ++;
157                *candidates_by_name[id] += out.size();
158        }
159
160        return out;
161}
162
163std::vector<SymbolTable::IdData> SymbolTable::specialLookupId( SymbolTable::SpecialFunctionKind kind, const std::string & otypeKey ) const {
164        static Stats::Counters::CounterGroup * special_stats = Stats::Counters::build<Stats::Counters::CounterGroup>("Special Lookups");
165        static Stats::Counters::SimpleCounter * stat_counts[3] = {
166                Stats::Counters::build<Stats::Counters::SimpleCounter>("constructor - count", special_stats),
167                Stats::Counters::build<Stats::Counters::SimpleCounter>("destructor - count", special_stats),
168                Stats::Counters::build<Stats::Counters::SimpleCounter>("assignment - count", special_stats)
169        };
170
171        static Stats::Counters::SimpleCounter * stat_candidates[3] = {
172                Stats::Counters::build<Stats::Counters::SimpleCounter>("constructor - candidates", special_stats),
173                Stats::Counters::build<Stats::Counters::SimpleCounter>("destructor - candidates", special_stats),
174                Stats::Counters::build<Stats::Counters::SimpleCounter>("assignment - candidates", special_stats)
175        };
176
177        static Stats::Counters::SimpleCounter * num_lookup_with_key
178                = Stats::Counters::build<Stats::Counters::SimpleCounter>("keyed lookups", special_stats);
179        static Stats::Counters::SimpleCounter * num_lookup_without_key
180                = Stats::Counters::build<Stats::Counters::SimpleCounter>("unkeyed lookups", special_stats);
181
182        assert (kind != NUMBER_OF_KINDS);
183        ++*stats().lookup_calls;
184        if ( ! specialFunctionTable[kind] ) return {};
185
186        std::vector<IdData> out;
187
188        if (otypeKey.empty()) { // returns everything
189                ++*num_lookup_without_key;
190                for (auto & table : *specialFunctionTable[kind]) {
191                        for (auto & decl : *table.second) {
192                                out.push_back(decl.second);
193                        }
194                }
195        }
196        else {
197                ++*num_lookup_with_key;
198                ++*stats().map_lookups;
199                auto decls = specialFunctionTable[kind]->find(otypeKey);
200                if (decls == specialFunctionTable[kind]->end()) return {};
201
202                for (auto decl : *(decls->second)) {
203                        out.push_back(decl.second);
204                }
205        }
206
207        ++*stat_counts[kind];
208        *stat_candidates[kind] += out.size();
209
210        return out;
211}
212
213const NamedTypeDecl * SymbolTable::lookupType( const std::string &id ) const {
214        ++*stats().lookup_calls;
215        if ( ! typeTable ) return nullptr;
216        ++*stats().map_lookups;
217        auto it = typeTable->find( id );
218        return it == typeTable->end() ? nullptr : it->second.decl;
219}
220
221const StructDecl * SymbolTable::lookupStruct( const std::string &id ) const {
222        ++*stats().lookup_calls;
223        if ( ! structTable ) return nullptr;
224        ++*stats().map_lookups;
225        auto it = structTable->find( id );
226        return it == structTable->end() ? nullptr : it->second.decl;
227}
228
229const EnumDecl * SymbolTable::lookupEnum( const std::string &id ) const {
230        ++*stats().lookup_calls;
231        if ( ! enumTable ) return nullptr;
232        ++*stats().map_lookups;
233        auto it = enumTable->find( id );
234        return it == enumTable->end() ? nullptr : it->second.decl;
235}
236
237const UnionDecl * SymbolTable::lookupUnion( const std::string &id ) const {
238        ++*stats().lookup_calls;
239        if ( ! unionTable ) return nullptr;
240        ++*stats().map_lookups;
241        auto it = unionTable->find( id );
242        return it == unionTable->end() ? nullptr : it->second.decl;
243}
244
245const TraitDecl * SymbolTable::lookupTrait( const std::string &id ) const {
246        ++*stats().lookup_calls;
247        if ( ! traitTable ) return nullptr;
248        ++*stats().map_lookups;
249        auto it = traitTable->find( id );
250        return it == traitTable->end() ? nullptr : it->second.decl;
251}
252
253const NamedTypeDecl * SymbolTable::globalLookupType( const std::string &id ) const {
254        return atScope( 0 )->lookupType( id );
255}
256
257const StructDecl * SymbolTable::globalLookupStruct( const std::string &id ) const {
258        return atScope( 0 )->lookupStruct( id );
259}
260
261const UnionDecl * SymbolTable::globalLookupUnion( const std::string &id ) const {
262        return atScope( 0 )->lookupUnion( id );
263}
264
265const EnumDecl * SymbolTable::globalLookupEnum( const std::string &id ) const {
266        return atScope( 0 )->lookupEnum( id );
267}
268
269void SymbolTable::addId( const DeclWithType * decl, const Expr * baseExpr ) {
270        // default handling of conflicts is to raise an error
271        addIdCommon( decl, OnConflict::error(), baseExpr, decl->isDeleted ? decl : nullptr );
272}
273
274void SymbolTable::addDeletedId( const DeclWithType * decl, const Decl * deleter ) {
275        // default handling of conflicts is to raise an error
276        addIdCommon( decl, OnConflict::error(), nullptr, deleter );
277}
278
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 ) {
284                return true;
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;
304}
305
306void SymbolTable::addType( const NamedTypeDecl * decl ) {
307        ++*stats().add_calls;
308        const std::string &id = decl->name;
309
310        if ( ! typeTable ) {
311                typeTable = TypeTable::new_ptr();
312        } else {
313                ++*stats().map_lookups;
314                auto existing = typeTable->find( id );
315                if ( existing != typeTable->end()
316                        && existing->second.scope == scope
317                        && addedTypeConflicts( existing->second.decl, decl ) ) return;
318        }
319
320        lazyInitScope();
321        ++*stats().map_mutations;
322        typeTable = typeTable->set( id, scoped<NamedTypeDecl>{ decl, scope } );
323}
324
325void SymbolTable::addStruct( const std::string &id ) {
326        addStruct( new StructDecl( CodeLocation(), id ) );
327}
328
329void SymbolTable::addStruct( const StructDecl * decl ) {
330        ++*stats().add_calls;
331        const std::string &id = decl->name;
332
333        if ( ! structTable ) {
334                structTable = StructTable::new_ptr();
335        } else {
336                ++*stats().map_lookups;
337                auto existing = structTable->find( id );
338                if ( existing != structTable->end()
339                        && existing->second.scope == scope
340                        && addedDeclConflicts( existing->second.decl, decl ) ) return;
341        }
342
343        lazyInitScope();
344        ++*stats().map_mutations;
345        structTable = structTable->set( id, scoped<StructDecl>{ decl, scope } );
346}
347
348void SymbolTable::addEnum( const EnumDecl *decl ) {
349        ++*stats().add_calls;
350        const std::string &id = decl->name;
351
352        if ( ! enumTable ) {
353                enumTable = EnumTable::new_ptr();
354        } else {
355                ++*stats().map_lookups;
356                auto existing = enumTable->find( id );
357                if ( existing != enumTable->end()
358                        && existing->second.scope == scope
359                        && addedDeclConflicts( existing->second.decl, decl ) ) return;
360        }
361
362        lazyInitScope();
363        ++*stats().map_mutations;
364        enumTable = enumTable->set( id, scoped<EnumDecl>{ decl, scope } );
365}
366
367void SymbolTable::addUnion( const std::string &id ) {
368        addUnion( new UnionDecl( CodeLocation(), id ) );
369}
370
371void SymbolTable::addUnion( const UnionDecl * decl ) {
372        ++*stats().add_calls;
373        const std::string &id = decl->name;
374
375        if ( ! unionTable ) {
376                unionTable = UnionTable::new_ptr();
377        } else {
378                ++*stats().map_lookups;
379                auto existing = unionTable->find( id );
380                if ( existing != unionTable->end()
381                        && existing->second.scope == scope
382                        && addedDeclConflicts( existing->second.decl, decl ) ) return;
383        }
384
385        lazyInitScope();
386        ++*stats().map_mutations;
387        unionTable = unionTable->set( id, scoped<UnionDecl>{ decl, scope } );
388}
389
390void SymbolTable::addTrait( const TraitDecl * decl ) {
391        ++*stats().add_calls;
392        const std::string &id = decl->name;
393
394        if ( ! traitTable ) {
395                traitTable = TraitTable::new_ptr();
396        } else {
397                ++*stats().map_lookups;
398                auto existing = traitTable->find( id );
399                if ( existing != traitTable->end()
400                        && existing->second.scope == scope
401                        && addedDeclConflicts( existing->second.decl, decl ) ) return;
402        }
403
404        lazyInitScope();
405        ++*stats().map_mutations;
406        traitTable = traitTable->set( id, scoped<TraitDecl>{ decl, scope } );
407}
408
409
410void SymbolTable::addWith( const std::vector< ptr<Expr> > & withExprs, const Decl * withStmt ) {
411        for ( const Expr * expr : withExprs ) {
412                if ( ! expr->result ) continue;
413                const Type * resTy = expr->result->stripReferences();
414                auto aggrType = dynamic_cast< const BaseInstType * >( resTy );
415                assertf( aggrType, "WithStmt expr has non-aggregate type: %s",
416                        toString( expr->result ).c_str() );
417                const AggregateDecl * aggr = aggrType->aggr();
418                assertf( aggr, "WithStmt has null aggregate from type: %s",
419                        toString( expr->result ).c_str() );
420
421                addMembers( aggr, expr, OnConflict::deleteWith( withStmt ) );
422        }
423}
424
425void SymbolTable::addIds( const std::vector< ptr<DeclWithType> > & decls ) {
426        for ( const DeclWithType * decl : decls ) { addId( decl ); }
427}
428
429void SymbolTable::addTypes( const std::vector< ptr<TypeDecl> > & tds ) {
430        for ( const TypeDecl * td : tds ) {
431                addType( td );
432                addIds( td->assertions );
433        }
434}
435
436
437void SymbolTable::addFunction( const FunctionDecl * func ) {
438        for (auto & td : func->type_params) {
439                addType(td);
440        }
441        for (auto & asst : func->assertions) {
442                addId(asst);
443        }
444        // addTypes( func->type->forall );
445        addIds( func->returns );
446        addIds( func->params );
447}
448
449
450void SymbolTable::lazyInitScope() {
451        // do nothing if already in represented scope
452        if ( repScope == scope ) return;
453
454        ++*stats().lazy_scopes;
455        // create rollback
456        prevScope = std::make_shared<SymbolTable>( *this );
457        // update repScope
458        repScope = scope;
459}
460
461const ast::SymbolTable * SymbolTable::atScope( unsigned long target ) const {
462        // by lazy construction, final symtab in list has repScope 0, cannot be > target
463        // otherwise, will find first scope representing the target
464        const SymbolTable * symtab = this;
465        while ( symtab->repScope > target ) {
466                symtab = symtab->prevScope.get();
467        }
468        return symtab;
469}
470
471namespace {
472        /// gets the base type of the first parameter; decl must be a ctor/dtor/assignment function
473        std::string getOtypeKey( const FunctionType * ftype, bool stripParams = true ) {
474                const auto & params = ftype->params;
475                assert( ! params.empty() );
476                // use base type of pointer, so that qualifiers on the pointer type aren't considered.
477                const Type * base = ast::getPointerBase( params.front() );
478                assert( base );
479                if (stripParams) {
480                        if (dynamic_cast<const PointerType *>(base)) return Mangle::Encoding::pointer;
481                        return Mangle::mangle( base, Mangle::Type | Mangle::NoGenericParams );
482                }
483                else
484                        return Mangle::mangle( base ); 
485        }
486
487        /// gets the declaration for the function acting on a type specified by otype key,
488        /// nullptr if none such
489        const FunctionDecl * getFunctionForOtype(
490                        const DeclWithType * decl, const std::string & otypeKey ) {
491                auto func = dynamic_cast< const FunctionDecl * >( decl );
492                if ( ! func || otypeKey != getOtypeKey( func->type, false ) ) return nullptr;
493                return func;
494        }
495}
496
497bool SymbolTable::removeSpecialOverrides(
498                SymbolTable::IdData & data, SymbolTable::MangleTable::Ptr & mangleTable ) {
499        // if a type contains user defined ctor/dtor/assign, then special rules trigger, which
500        // determine the set of ctor/dtor/assign that can be used  by the requester. In particular,
501        // if the user defines a default ctor, then the generated default ctor is unavailable,
502        // likewise for copy ctor and dtor. If the user defines any ctor/dtor, then no generated
503        // field ctors are available. If the user defines any ctor then the generated default ctor
504        // is unavailable (intrinsic default ctor must be overridden exactly). If the user defines
505        // anything that looks like a copy constructor, then the generated copy constructor is
506        // unavailable, and likewise for the assignment operator.
507
508        // only relevant on function declarations
509        const FunctionDecl * function = data.id.as< FunctionDecl >();
510        if ( ! function ) return true;
511        // only need to perform this check for constructors, destructors, and assignment functions
512        if ( ! CodeGen::isCtorDtorAssign( data.id->name ) ) return true;
513
514        // set up information for this type
515        bool dataIsUserDefinedFunc = ! function->linkage.is_overrideable;
516        bool dataIsCopyFunc = InitTweak::isCopyFunction( function );
517        std::string dataOtypeKey = getOtypeKey( function->type, false ); // requires exact match to override autogen
518
519        if ( dataIsUserDefinedFunc && dataIsCopyFunc ) {
520                // this is a user-defined copy function
521                // if this is the first such, delete/remove non-user-defined overloads as needed
522                std::vector< std::string > removed;
523                std::vector< MangleTable::value_type > deleted;
524                bool alreadyUserDefinedFunc = false;
525
526                for ( const auto& entry : *mangleTable ) {
527                        // skip decls that aren't functions or are for the wrong type
528                        const FunctionDecl * decl = getFunctionForOtype( entry.second.id, dataOtypeKey );
529                        if ( ! decl ) continue;
530
531                        bool isCopyFunc = InitTweak::isCopyFunction( decl );
532                        if ( ! decl->linkage.is_overrideable ) {
533                                // matching user-defined function
534                                if ( isCopyFunc ) {
535                                        // mutation already performed, return early
536                                        return true;
537                                } else {
538                                        // note that non-copy deletions already performed
539                                        alreadyUserDefinedFunc = true;
540                                }
541                        } else {
542                                // non-user-defined function; mark for deletion/removal as appropriate
543                                if ( isCopyFunc ) {
544                                        removed.push_back( entry.first );
545                                } else if ( ! alreadyUserDefinedFunc ) {
546                                        deleted.push_back( entry );
547                                }
548                        }
549                }
550
551                // perform removals from mangle table, and deletions if necessary
552                for ( const auto& key : removed ) {
553                        ++*stats().map_mutations;
554                        mangleTable = mangleTable->erase( key );
555                }
556                if ( ! alreadyUserDefinedFunc ) for ( const auto& entry : deleted ) {
557                        ++*stats().map_mutations;
558                        mangleTable = mangleTable->set( entry.first, IdData{ entry.second, function } );
559                }
560        } else if ( dataIsUserDefinedFunc ) {
561                // this is a user-defined non-copy function
562                // if this is the first user-defined function, delete non-user-defined overloads
563                std::vector< MangleTable::value_type > deleted;
564
565                for ( const auto& entry : *mangleTable ) {
566                        // skip decls that aren't functions or are for the wrong type
567                        const FunctionDecl * decl = getFunctionForOtype( entry.second.id, dataOtypeKey );
568                        if ( ! decl ) continue;
569
570                        // exit early if already a matching user-defined function;
571                        // earlier function will have mutated table
572                        if ( ! decl->linkage.is_overrideable ) return true;
573
574                        // skip mutating intrinsic functions
575                        if ( decl->linkage == Linkage::Intrinsic ) continue;
576
577                        // user-defined non-copy functions do not override copy functions
578                        if ( InitTweak::isCopyFunction( decl ) ) continue;
579
580                        // this function to be deleted after mangleTable iteration is complete
581                        deleted.push_back( entry );
582                }
583
584                // mark deletions to update mangle table
585                // this needs to be a separate loop because of iterator invalidation
586                for ( const auto& entry : deleted ) {
587                        ++*stats().map_mutations;
588                        mangleTable = mangleTable->set( entry.first, IdData{ entry.second, function } );
589                }
590        } else if ( function->linkage != Linkage::Intrinsic ) {
591                // this is an overridable generated function
592                // if there already exists a matching user-defined function, delete this appropriately
593                for ( const auto& entry : *mangleTable ) {
594                        // skip decls that aren't functions or are for the wrong type
595                        const FunctionDecl * decl = getFunctionForOtype( entry.second.id, dataOtypeKey );
596                        if ( ! decl ) continue;
597
598                        // skip non-user-defined functions
599                        if ( decl->linkage.is_overrideable ) continue;
600
601                        if ( dataIsCopyFunc ) {
602                                // remove current function if exists a user-defined copy function
603                                // since the signatures for copy functions don't need to match exactly, using
604                                // a delete statement is the wrong approach
605                                if ( InitTweak::isCopyFunction( decl ) ) return false;
606                        } else {
607                                // mark current function deleted by first user-defined function found
608                                data.deleter = decl;
609                                return true;
610                        }
611                }
612        }
613
614        // nothing (more) to fix, return true
615        return true;
616}
617
618namespace {
619        /// true iff the declaration represents a function
620        bool isFunction( const DeclWithType * decl ) {
621                return GenPoly::getFunctionType( decl->get_type() );
622        }
623
624        bool isObject( const DeclWithType * decl ) { return ! isFunction( decl ); }
625
626        /// true if the declaration represents a definition instead of a forward decl
627        bool isDefinition( const DeclWithType * decl ) {
628                if ( auto func = dynamic_cast< const FunctionDecl * >( decl ) ) {
629                        // a function is a definition if it has a body
630                        return func->stmts;
631                } else {
632                        // an object is a definition if it is not marked extern
633                        return ! decl->storage.is_extern;
634                }
635        }
636}
637
638bool SymbolTable::addedIdConflicts(
639                const SymbolTable::IdData & existing, const DeclWithType * added,
640                SymbolTable::OnConflict handleConflicts, const Decl * deleter ) {
641        // if we're giving the same name mangling to things of different types then there is something
642        // wrong
643        assert( (isObject( added ) && isObject( existing.id ) )
644                || ( isFunction( added ) && isFunction( existing.id ) ) );
645
646        if ( existing.id->linkage.is_overrideable ) {
647                // new definition shadows the autogenerated one, even at the same scope
648                return false;
649        } else if ( existing.id->linkage.is_mangled
650                        || ResolvExpr::typesCompatible(
651                                added->get_type(), existing.id->get_type() ) ) {
652
653                // it is a conflict if one declaration is deleted and the other is not
654                if ( deleter && ! existing.deleter ) {
655                        if ( handleConflicts.mode == OnConflict::Error ) {
656                                OnFindError( added, "deletion of defined identifier " );
657                        }
658                        return true;
659                } else if ( ! deleter && existing.deleter ) {
660                        if ( handleConflicts.mode == OnConflict::Error ) {
661                                OnFindError( added, "definition of deleted identifier " );
662                        }
663                        return true;
664                }
665
666                // it is a conflict if both declarations are definitions
667                if ( isDefinition( added ) && isDefinition( existing.id ) ) {
668                        if ( handleConflicts.mode == OnConflict::Error ) {
669                                OnFindError( added,
670                                        isFunction( added ) ?
671                                                "duplicate function definition for " :
672                                                "duplicate object definition for " );
673                        }
674                        return true;
675                }
676        } else {
677                if ( handleConflicts.mode == OnConflict::Error ) {
678                        OnFindError( added, "duplicate definition for " );
679                }
680                return true;
681        }
682
683        return true;
684}
685
686void SymbolTable::addIdCommon(
687                const DeclWithType * decl, SymbolTable::OnConflict handleConflicts,
688                const Expr * baseExpr, const Decl * deleter ) {
689        SpecialFunctionKind kind = getSpecialFunctionKind(decl->name);
690        if (kind == NUMBER_OF_KINDS) { // not a special decl
691                addIdToTable(decl, decl->name, idTable, handleConflicts, baseExpr, deleter);
692        }
693        else {
694                std::string key;
695                if (auto func = dynamic_cast<const FunctionDecl *>(decl)) {
696                        key = getOtypeKey(func->type);
697                }
698                else if (auto obj = dynamic_cast<const ObjectDecl *>(decl)) {
699                        key = getOtypeKey(obj->type.strict_as<PointerType>()->base.strict_as<FunctionType>());
700                }
701                else {
702                        assertf(false, "special decl with non-function type");
703                }
704                addIdToTable(decl, key, specialFunctionTable[kind], handleConflicts, baseExpr, deleter);
705        }
706}
707
708void SymbolTable::addIdToTable(
709                const DeclWithType * decl, const std::string & lookupKey,
710                IdTable::Ptr & table, SymbolTable::OnConflict handleConflicts,
711                const Expr * baseExpr, const Decl * deleter ) {
712        ++*stats().add_calls;
713        const std::string &name = decl->name;
714        if ( name == "" ) return;
715
716        std::string mangleName;
717        if ( decl->linkage.is_overrideable ) {
718                // mangle the name without including the appropriate suffix, so overridable routines
719                // are placed into the same "bucket" as their user defined versions.
720                mangleName = Mangle::mangle( decl, Mangle::Mode{ Mangle::NoOverrideable } );
721        } else {
722                mangleName = Mangle::mangle( decl );
723        }
724
725        // this ensures that no two declarations with the same unmangled name at the same scope
726        // both have C linkage
727        if ( decl->linkage.is_mangled ) {
728                // Check that a Cforall declaration doesn't override any C declaration
729                if ( hasCompatibleCDecl( name, mangleName ) ) {
730                        OnFindError( decl, "Cforall declaration hides C function " );
731                }
732        } else {
733                // NOTE: only correct if name mangling is completely isomorphic to C
734                // type-compatibility, which it may not be.
735                if ( hasIncompatibleCDecl( name, mangleName ) ) {
736                        OnFindError( decl, "conflicting overload of C function " );
737                }
738        }
739
740        // ensure tables exist and add identifier
741        MangleTable::Ptr mangleTable;
742        if ( ! table ) {
743                table = IdTable::new_ptr();
744                mangleTable = MangleTable::new_ptr();
745        } else {
746                ++*stats().map_lookups;
747                auto decls = table->find( lookupKey );
748                if ( decls == table->end() ) {
749                        mangleTable = MangleTable::new_ptr();
750                } else {
751                        mangleTable = decls->second;
752                        // skip in-scope repeat declarations of same identifier
753                        ++*stats().map_lookups;
754                        auto existing = mangleTable->find( mangleName );
755                        if ( existing != mangleTable->end()
756                                        && existing->second.scope == scope
757                                        && existing->second.id ) {
758                                if ( addedIdConflicts( existing->second, decl, handleConflicts, deleter ) ) {
759                                        if ( handleConflicts.mode == OnConflict::Delete ) {
760                                                // set delete expression for conflicting identifier
761                                                lazyInitScope();
762                                                *stats().map_mutations += 2;
763                                                table = table->set(
764                                                        lookupKey,
765                                                        mangleTable->set(
766                                                                mangleName,
767                                                                IdData{ existing->second, handleConflicts.deleter } ) );
768                                        }
769                                        return;
770                                }
771                        }
772                }
773        }
774
775        // add/overwrite with new identifier
776        lazyInitScope();
777        IdData data{ decl, baseExpr, deleter, scope };
778        // Ensure that auto-generated ctor/dtor/assignment are deleted if necessary
779        if (table != idTable) { // adding to special table
780                if ( ! removeSpecialOverrides( data, mangleTable ) ) return;
781        }
782        *stats().map_mutations += 2;
783        table = table->set( lookupKey, mangleTable->set( mangleName, std::move(data) ) );
784}
785
786void SymbolTable::addMembers(
787                const AggregateDecl * aggr, const Expr * expr, SymbolTable::OnConflict handleConflicts ) {
788        for ( const ptr<Decl> & decl : aggr->members ) {
789                auto dwt = decl.as<DeclWithType>();
790                if ( nullptr == dwt ) continue;
791                addIdCommon( dwt, handleConflicts, expr );
792                // Inline through unnamed struct/union members.
793                if ( "" != dwt->name ) continue;
794                const Type * t = dwt->get_type()->stripReferences();
795                if ( auto rty = dynamic_cast<const BaseInstType *>( t ) ) {
796                        if ( ! dynamic_cast<const StructInstType *>(rty)
797                                && ! dynamic_cast<const UnionInstType *>(rty) ) continue;
798                        ResolvExpr::Cost cost = ResolvExpr::Cost::zero;
799                        ast::ptr<ast::TypeSubstitution> tmp = expr->env;
800                        expr = mutate_field(expr, &Expr::env, nullptr);
801                        const Expr * base = ResolvExpr::referenceToRvalueConversion( expr, cost );
802                        base = mutate_field(base, &Expr::env, tmp);
803
804                        addMembers(
805                                rty->aggr(), new MemberExpr{ base->location, dwt, base }, handleConflicts );
806                }
807        }
808}
809
810bool SymbolTable::hasCompatibleCDecl( const std::string &id, const std::string &mangleName ) const {
811        if ( ! idTable ) return false;
812
813        ++*stats().map_lookups;
814        auto decls = idTable->find( id );
815        if ( decls == idTable->end() ) return false;
816
817        for ( auto decl : *(decls->second) ) {
818                // skip other scopes (hidden by this decl)
819                if ( decl.second.scope != scope ) continue;
820                // check for C decl with compatible type (by mangleName)
821                if ( ! decl.second.id->linkage.is_mangled && decl.first == mangleName ) return true;
822        }
823
824        return false;
825}
826
827bool SymbolTable::hasIncompatibleCDecl( const std::string &id, const std::string &mangleName ) const {
828        if ( ! idTable ) return false;
829
830        ++*stats().map_lookups;
831        auto decls = idTable->find( id );
832        if ( decls == idTable->end() ) return false;
833
834        for ( auto decl : *(decls->second) ) {
835                // skip other scopes (hidden by this decl)
836                if ( decl.second.scope != scope ) continue;
837                // check for C decl with incompatible type (by manglename)
838                if ( ! decl.second.id->linkage.is_mangled && decl.first != mangleName ) return true;
839        }
840
841        return false;
842}
843
844}
845
846// Local Variables: //
847// tab-width: 4 //
848// mode: c++ //
849// compile-command: "make install" //
850// End: //
Note: See TracBrowser for help on using the repository browser.