source: src/AST/SymbolTable.cpp@ 994030ce

Last change on this file since 994030ce was b9fe89b, checked in by Michael Brooks <mlbrooks@…>, 2 years 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
RevLine 
[d76c588]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
[bccd70a]20#include "Copy.hpp"
[d76c588]21#include "Decl.hpp"
22#include "Expr.hpp"
[e01eb4a]23#include "Inspect.hpp"
[d76c588]24#include "Type.hpp"
[fed6a0f]25#include "CodeGen/OperatorTable.h" // for isCtorDtorAssign
[d76c588]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"
[fed6a0f]31#include "ResolvExpr/CandidateFinder.hpp" // for referenceToRvalueConversion
[e563edf]32#include "ResolvExpr/Unify.h"
[d76c588]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 {
[9e23b446]70 Expr * ret;
71 if ( baseExpr ) {
72 if (baseExpr->env) {
[bb7422a]73 Expr * base = deepCopy(baseExpr);
[9e23b446]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 }
[d76c588]86 if ( deleter ) { ret = new DeletedExpr{ loc, ret, deleter }; }
87 return ret;
88}
89
[b9fe89b]90SymbolTable::SymbolTable( ErrorDetection errorMode )
[e67991f]91: idTable(), typeTable(), structTable(), enumTable(), unionTable(), traitTable(),
[b9fe89b]92 prevScope(), scope( 0 ), repScope( 0 ), errorMode(errorMode) { ++*stats().count; }
[d76c588]93
94SymbolTable::~SymbolTable() { stats().size->push( idTable ? idTable->size() : 0 ); }
95
[b9fe89b]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
[d76c588]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
[e5c3811]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
[d76c588]128std::vector<SymbolTable::IdData> SymbolTable::lookupId( const std::string &id ) const {
[e5c3811]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
[d76c588]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 }
[e5c3811]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
[d76c588]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
[d859a30]271 addIdCommon( decl, OnConflict::error(), baseExpr, decl->isDeleted ? decl : nullptr );
[d76c588]272}
273
[e67991f]274void SymbolTable::addDeletedId( const DeclWithType * decl, const Decl * deleter ) {
[d76c588]275 // default handling of conflicts is to raise an error
[d859a30]276 addIdCommon( decl, OnConflict::error(), nullptr, deleter );
[d76c588]277}
278
[b9fe89b]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 ) {
[d76c588]284 return true;
[b9fe89b]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 }
[d76c588]290 }
[b9fe89b]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}
[d76c588]295
[b9fe89b]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 " );
[d76c588]302 }
[b9fe89b]303 return true;
[d76c588]304}
305
306void SymbolTable::addType( const NamedTypeDecl * decl ) {
307 ++*stats().add_calls;
308 const std::string &id = decl->name;
309
[e67991f]310 if ( ! typeTable ) {
[d76c588]311 typeTable = TypeTable::new_ptr();
312 } else {
313 ++*stats().map_lookups;
314 auto existing = typeTable->find( id );
[e67991f]315 if ( existing != typeTable->end()
316 && existing->second.scope == scope
[d76c588]317 && addedTypeConflicts( existing->second.decl, decl ) ) return;
318 }
[e67991f]319
[d76c588]320 lazyInitScope();
321 ++*stats().map_mutations;
322 typeTable = typeTable->set( id, scoped<NamedTypeDecl>{ decl, scope } );
323}
324
325void SymbolTable::addStruct( const std::string &id ) {
[4b8b2a4]326 addStruct( new StructDecl( CodeLocation(), id ) );
[d76c588]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 );
[e67991f]338 if ( existing != structTable->end()
339 && existing->second.scope == scope
[d76c588]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 );
[e67991f]357 if ( existing != enumTable->end()
358 && existing->second.scope == scope
[d76c588]359 && addedDeclConflicts( existing->second.decl, decl ) ) return;
360 }
[e67991f]361
[d76c588]362 lazyInitScope();
363 ++*stats().map_mutations;
364 enumTable = enumTable->set( id, scoped<EnumDecl>{ decl, scope } );
365}
366
367void SymbolTable::addUnion( const std::string &id ) {
[4b8b2a4]368 addUnion( new UnionDecl( CodeLocation(), id ) );
[d76c588]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 );
[e67991f]380 if ( existing != unionTable->end()
381 && existing->second.scope == scope
[d76c588]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 );
[e67991f]399 if ( existing != traitTable->end()
400 && existing->second.scope == scope
[d76c588]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
[e67991f]410void SymbolTable::addWith( const std::vector< ptr<Expr> > & withExprs, const Decl * withStmt ) {
[d76c588]411 for ( const Expr * expr : withExprs ) {
412 if ( ! expr->result ) continue;
413 const Type * resTy = expr->result->stripReferences();
[98e8b3b]414 auto aggrType = dynamic_cast< const BaseInstType * >( resTy );
[e67991f]415 assertf( aggrType, "WithStmt expr has non-aggregate type: %s",
[d76c588]416 toString( expr->result ).c_str() );
417 const AggregateDecl * aggr = aggrType->aggr();
[e67991f]418 assertf( aggr, "WithStmt has null aggregate from type: %s",
[d76c588]419 toString( expr->result ).c_str() );
[e67991f]420
[d76c588]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
[490fb92e]436
437void SymbolTable::addFunction( const FunctionDecl * func ) {
[3e5dd913]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 );
[490fb92e]445 addIds( func->returns );
446 addIds( func->params );
[d76c588]447}
[490fb92e]448
[d76c588]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
[e5c3811]473 std::string getOtypeKey( const FunctionType * ftype, bool stripParams = true ) {
474 const auto & params = ftype->params;
[d76c588]475 assert( ! params.empty() );
476 // use base type of pointer, so that qualifiers on the pointer type aren't considered.
[e01eb4a]477 const Type * base = ast::getPointerBase( params.front() );
[d76c588]478 assert( base );
[e5c3811]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 );
[d76c588]485 }
486
[e67991f]487 /// gets the declaration for the function acting on a type specified by otype key,
[d76c588]488 /// nullptr if none such
[e67991f]489 const FunctionDecl * getFunctionForOtype(
[d76c588]490 const DeclWithType * decl, const std::string & otypeKey ) {
491 auto func = dynamic_cast< const FunctionDecl * >( decl );
[e5c3811]492 if ( ! func || otypeKey != getOtypeKey( func->type, false ) ) return nullptr;
[d76c588]493 return func;
494 }
495}
496
[e67991f]497bool SymbolTable::removeSpecialOverrides(
[d76c588]498 SymbolTable::IdData & data, SymbolTable::MangleTable::Ptr & mangleTable ) {
[e67991f]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
[d76c588]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 );
[e5c3811]517 std::string dataOtypeKey = getOtypeKey( function->type, false ); // requires exact match to override autogen
[d76c588]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;
[e67991f]564
[d76c588]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
[e67991f]603 // since the signatures for copy functions don't need to match exactly, using
[d76c588]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 }
[e67991f]613
[d76c588]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(
[e67991f]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
[d76c588]642 // wrong
643 assert( (isObject( added ) && isObject( existing.id ) )
644 || ( isFunction( added ) && isFunction( existing.id ) ) );
[e67991f]645
[d76c588]646 if ( existing.id->linkage.is_overrideable ) {
647 // new definition shadows the autogenerated one, even at the same scope
648 return false;
[e67991f]649 } else if ( existing.id->linkage.is_mangled
650 || ResolvExpr::typesCompatible(
[251ce80]651 added->get_type(), existing.id->get_type() ) ) {
[e67991f]652
[d76c588]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 ) {
[b9fe89b]656 OnFindError( added, "deletion of defined identifier " );
[d76c588]657 }
658 return true;
659 } else if ( ! deleter && existing.deleter ) {
660 if ( handleConflicts.mode == OnConflict::Error ) {
[b9fe89b]661 OnFindError( added, "definition of deleted identifier " );
[d76c588]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 ) {
[b9fe89b]669 OnFindError( added,
[e67991f]670 isFunction( added ) ?
671 "duplicate function definition for " :
[d76c588]672 "duplicate object definition for " );
673 }
674 return true;
675 }
676 } else {
677 if ( handleConflicts.mode == OnConflict::Error ) {
[b9fe89b]678 OnFindError( added, "duplicate definition for " );
[d76c588]679 }
680 return true;
681 }
682
683 return true;
684}
685
[d859a30]686void SymbolTable::addIdCommon(
687 const DeclWithType * decl, SymbolTable::OnConflict handleConflicts,
688 const Expr * baseExpr, const Decl * deleter ) {
[e5c3811]689 SpecialFunctionKind kind = getSpecialFunctionKind(decl->name);
690 if (kind == NUMBER_OF_KINDS) { // not a special decl
[d859a30]691 addIdToTable(decl, decl->name, idTable, handleConflicts, baseExpr, deleter);
[e5c3811]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 }
[d859a30]704 addIdToTable(decl, key, specialFunctionTable[kind], handleConflicts, baseExpr, deleter);
[e5c3811]705 }
706}
707
[d859a30]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 ) {
[d76c588]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 ) {
[e67991f]718 // mangle the name without including the appropriate suffix, so overridable routines
[d76c588]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
[e67991f]725 // this ensures that no two declarations with the same unmangled name at the same scope
[d76c588]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 ) ) {
[b9fe89b]730 OnFindError( decl, "Cforall declaration hides C function " );
[d76c588]731 }
732 } else {
[e67991f]733 // NOTE: only correct if name mangling is completely isomorphic to C
[d76c588]734 // type-compatibility, which it may not be.
735 if ( hasIncompatibleCDecl( name, mangleName ) ) {
[b9fe89b]736 OnFindError( decl, "conflicting overload of C function " );
[d76c588]737 }
738 }
739
740 // ensure tables exist and add identifier
741 MangleTable::Ptr mangleTable;
[e5c3811]742 if ( ! table ) {
743 table = IdTable::new_ptr();
[d76c588]744 mangleTable = MangleTable::new_ptr();
745 } else {
746 ++*stats().map_lookups;
[e5c3811]747 auto decls = table->find( lookupKey );
748 if ( decls == table->end() ) {
[d76c588]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;
[e5c3811]763 table = table->set(
764 lookupKey,
[e67991f]765 mangleTable->set(
766 mangleName,
[d76c588]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
[e5c3811]779 if (table != idTable) { // adding to special table
780 if ( ! removeSpecialOverrides( data, mangleTable ) ) return;
781 }
[d76c588]782 *stats().map_mutations += 2;
[e5c3811]783 table = table->set( lookupKey, mangleTable->set( mangleName, std::move(data) ) );
[d76c588]784}
785
[e67991f]786void SymbolTable::addMembers(
[d76c588]787 const AggregateDecl * aggr, const Expr * expr, SymbolTable::OnConflict handleConflicts ) {
[d859a30]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 );
[d76c588]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 }
[e67991f]823
[d76c588]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" //
[98e8b3b]850// End: //
Note: See TracBrowser for help on using the repository browser.