source: src/Validate/LinkReferenceToTypes.cpp @ 37273c8

Last change on this file since 37273c8 was 0d7fc00, checked in by Andrew Beach <ajbeach@…>, 16 months ago

This may fix the excessive 'struct _IO_FILE;' declarations. I still don't know how to replicate it on my machine.

  • Property mode set to 100644
File size: 10.5 KB
Line 
1//
2// Cforall Version 1.0.0 Copyright (C) 2018 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// LinkReferenceToTypes.cpp -- Connect instance types to declarations.
8//
9// Author           : Andrew Beach
10// Created On       : Thr Apr 21 11:41:00 2022
11// Last Modified By : Andrew Beach
12// Last Modified On : Fri Jul 14  9:19:00 2023
13// Update Count     : 3
14//
15
16#include "Validate/LinkReferenceToTypes.hpp"
17
18#include "AST/Pass.hpp"
19#include "AST/TranslationUnit.hpp"
20#include "Validate/ForallPointerDecay.hpp"
21#include "Validate/NoIdSymbolTable.hpp"
22
23namespace Validate {
24
25namespace {
26
27struct LinkTypesCore : public WithNoIdSymbolTable,
28                public ast::WithCodeLocation,
29                public ast::WithDeclsToAdd<>,
30                public ast::WithGuards,
31                public ast::WithShortCircuiting,
32                public ast::WithVisitorRef<LinkTypesCore> {
33        ast::TypeInstType const * postvisit( ast::TypeInstType const * type );
34        ast::EnumInstType const * postvisit( ast::EnumInstType const * type );
35        ast::StructInstType const * postvisit( ast::StructInstType const * type );
36        ast::UnionInstType const * postvisit( ast::UnionInstType const * type );
37        ast::TraitInstType const * postvisit( ast::TraitInstType const * type );
38        void previsit( ast::QualifiedType const * type );
39        void postvisit( ast::QualifiedType const * type );
40
41        ast::EnumDecl const * postvisit( ast::EnumDecl const * decl );
42        ast::StructDecl const * previsit( ast::StructDecl const * decl );
43        void postvisit( ast::StructDecl const * decl );
44        ast::UnionDecl const * previsit( ast::UnionDecl const * decl );
45        void postvisit( ast::UnionDecl const * decl );
46        ast::TraitDecl const * postvisit( ast::TraitDecl const * decl );
47
48private:
49        using ForwardStructsType =
50                std::map< std::string, std::list< ast::StructInstType * > >;
51        using ForwardUnionsType =
52                std::map< std::string, std::list< ast::UnionInstType * > >;
53        using ForwardEnumsType =
54                std::map< std::string, std::list< ast::EnumInstType * > >;
55
56        ForwardStructsType forwardStructs;
57        ForwardUnionsType forwardUnions;
58        ForwardEnumsType forwardEnums;
59
60        /// true if currently in a generic type body,
61        /// so that type parameter instances can be renamed appropriately
62        bool inGeneric = false;
63
64        template<typename AggrDecl>
65        AggrDecl const * renameGenericParams( AggrDecl const * decl );
66
67        // This cluster is used to add declarations (before) but outside of
68        // any "namespaces" which would qualify the names.
69        bool inNamespace = false;
70        std::list<ast::ptr<ast::Decl>> declsToAddOutside;
71        /// The "leaveNamespace" is handled by guard.
72        void enterNamespace();
73        /// Puts the decl on the back of declsToAddAfter once traversal is
74        /// outside of any namespaces.
75        void addDeclAfterOutside( ast::Decl const * );
76};
77
78void LinkTypesCore::enterNamespace() {
79        if ( inNamespace ) return;
80        inNamespace = true;
81        GuardAction( [this](){
82                inNamespace = false;
83                declsToAddAfter.splice( declsToAddAfter.begin(), declsToAddOutside );
84        } );
85}
86
87void LinkTypesCore::addDeclAfterOutside( ast::Decl const * decl ) {
88        if ( inNamespace ) {
89                declsToAddOutside.emplace_back( decl );
90        } else {
91                declsToAddAfter.emplace_back( decl );
92        }
93}
94
95ast::TypeInstType const * LinkTypesCore::postvisit( ast::TypeInstType const * type ) {
96        auto mut = ast::mutate( type );
97        if ( inGeneric && mut->base ) {
98                mut->name = mut->base->name;
99        }
100        if ( auto namedTypeDecl = symtab.lookupType( mut->name ) ) {
101                if ( auto typeDecl = dynamic_cast<ast::TypeDecl const *>( namedTypeDecl ) ) {
102                        mut->kind = typeDecl->kind;
103                }
104        }
105        return mut;
106}
107
108ast::EnumInstType const * LinkTypesCore::postvisit( ast::EnumInstType const * type ) {
109        ast::EnumDecl const * decl = symtab.lookupEnum( type->name );
110        // It's not a semantic error if the enum is not found, just an implicit forward declaration.
111        // The unset code location is used to detect imaginary declarations.
112        // (They may never be used for enumerations.)
113        if ( !decl || decl->location.isUnset() ) {
114                assert( location );
115                ast::EnumDecl * mut = new ast::EnumDecl( *location, type->name );
116                mut->linkage = ast::Linkage::Compiler;
117                decl = mut;
118                symtab.addEnum( decl );
119                addDeclAfterOutside( decl );
120        }
121
122        ast::EnumInstType * mut = ast::mutate( type );
123
124        // Just linking in the node.
125        mut->base = decl;
126
127        if ( !decl->body ) {
128                forwardEnums[ mut->name ].push_back( mut );
129        }
130        return mut;
131}
132
133ast::StructInstType const * LinkTypesCore::postvisit( ast::StructInstType const * type ) {
134        ast::StructDecl const * decl = symtab.lookupStruct( type->name );
135        // It's not a semantic error if the struct is not found, just an implicit forward declaration.
136        // The unset code location is used to detect imaginary declarations.
137        if ( !decl || decl->location.isUnset() ) {
138                assert( location );
139                ast::StructDecl * mut = new ast::StructDecl( *location, type->name );
140                mut->linkage = ast::Linkage::Compiler;
141                decl = mut;
142                symtab.addStruct( decl );
143                addDeclAfterOutside( decl );
144        }
145
146        ast::StructInstType * mut = ast::mutate( type );
147
148        // Just linking in the node.
149        mut->base = decl;
150
151        if ( !decl->body ) {
152                forwardStructs[ mut->name ].push_back( mut );
153        }
154        return mut;
155}
156
157ast::UnionInstType const * LinkTypesCore::postvisit( ast::UnionInstType const * type ) {
158        ast::UnionDecl const * decl = symtab.lookupUnion( type->name );
159        // It's not a semantic error if the union is not found, just an implicit forward declaration.
160        // The unset code location is used to detect imaginary declarations.
161        if ( !decl || decl->location.isUnset() ) {
162                assert( location );
163                ast::UnionDecl * mut = new ast::UnionDecl( *location, type->name );
164                mut->linkage = ast::Linkage::Compiler;
165                decl = mut;
166                symtab.addUnion( decl );
167                addDeclAfterOutside( decl );
168        }
169
170        ast::UnionInstType * mut = ast::mutate( type );
171
172        // Just linking in the node.
173        mut->base = decl;
174
175        if ( !decl->body ) {
176                forwardUnions[ mut->name ].push_back( mut );
177        }
178        return mut;
179}
180
181ast::TraitInstType const * LinkTypesCore::postvisit( ast::TraitInstType const * type ) {
182        assert( location );
183
184        ast::TraitDecl const * decl = symtab.lookupTrait( type->name );
185        if ( !decl ) {
186                SemanticError( *location, "use of undeclared trait " + type->name );
187        } else if ( decl->params.size() != type->params.size() ) {
188                SemanticError( *location, "incorrect number of trait parameters: " );
189        }
190        auto mut = ast::mutate( type );
191
192        // Just linking in the node.
193        mut->base = decl;
194
195        // Need to carry over the 'sized' status of each decl in the instance.
196        for ( auto p : group_iterate( decl->params, type->params ) ) {
197                ast::TypeExpr const * expr = std::get<1>(p).as<ast::TypeExpr>();
198                if ( !expr ) {
199                        SemanticError( std::get<1>(p).get(), "Expression parameters for trait instances are currently unsupported: " );
200                }
201                if ( auto inst = expr->type.as<ast::TypeInstType>() ) {
202                        ast::ptr<ast::TypeDecl> const & formalDecl = std::get<0>(p);
203                        if ( !formalDecl->sized ) {
204                                continue;
205                        }
206                        // To do this modification we need to reach through a readonly
207                        // pointer. The Pass doesn't quite work in that way, so we just
208                        // ensure it mutates in-place so it should work out.
209                        ast::TypeDecl const * base = inst->base.get();
210                        assert( base->unique() );
211                        ast::TypeDecl * mutBase = ast::mutate( base );
212                        mutBase->sized = true;
213                }
214        }
215        return mut;
216}
217
218void LinkTypesCore::previsit( ast::QualifiedType const * ) {
219        visit_children = false;
220}
221
222void LinkTypesCore::postvisit( ast::QualifiedType const * type ) {
223        // Linking only makes sense for the 'oldest ancestor' of the qualified type.
224        type->parent->accept( *visitor );
225}
226
227ast::EnumDecl const * LinkTypesCore::postvisit( ast::EnumDecl const * decl ) {
228        // After visiting enum members for self-referencing members,
229        // we replace the enum base. Right now it only works for StructDecl.
230        if ( decl->base ) {
231                if ( auto base = decl->base.as<ast::TypeInstType>() ) {
232                        if ( auto structDecl = symtab.lookupStruct( base->name ) ) {
233                                auto mut = ast::mutate( decl );
234                                mut->base = new ast::StructInstType( structDecl );
235                                decl = mut;
236                        }
237                        // visit the base
238                } else if ( auto ptr = decl->base.as<ast::PointerType>() ) {
239                        if ( auto base = ptr->base.as<ast::TypeInstType>() ) {
240                                if ( auto structDecl = symtab.lookupStruct( base->name ) ) {
241                                        auto mut = ast::mutate( decl );
242                                        mut->base = new ast::PointerType(
243                                                new ast::StructInstType( structDecl ) );
244                                        decl = mut;
245                                }
246                        }
247                }
248        }
249
250        // This section is common with struct/union, except for the return value.
251        if ( !decl->body ) {
252                return decl;
253        }
254
255        ForwardEnumsType::iterator fwds = forwardEnums.find( decl->name );
256        if ( fwds != forwardEnums.end() ) {
257                for ( auto inst : fwds->second ) {
258                        inst->base = decl;
259                }
260                forwardEnums.erase( fwds );
261        }
262
263        return decl;
264}
265
266template<typename AggrDecl>
267AggrDecl const * LinkTypesCore::renameGenericParams( AggrDecl const * decl ) {
268        GuardValue( inGeneric ) = !decl->params.empty();
269        if ( !inGeneric ) {
270                return decl;
271        }
272        auto mut = ast::mutate( decl );
273        for ( ast::ptr<ast::TypeDecl> & typeDecl : mut->params ) {
274                typeDecl.get_and_mutate()->name = "__" + typeDecl->name + "_generic_";
275        }
276        return mut;
277}
278
279ast::StructDecl const * LinkTypesCore::previsit( ast::StructDecl const * decl ) {
280        enterNamespace();
281        return renameGenericParams( decl );
282}
283
284void LinkTypesCore::postvisit( ast::StructDecl const * decl ) {
285        if ( !decl->body ) {
286                return;
287        }
288
289        ForwardStructsType::iterator fwds = forwardStructs.find( decl->name );
290        if ( fwds != forwardStructs.end() ) {
291                for ( auto inst : fwds->second ) {
292                        inst->base = decl;
293                }
294                forwardStructs.erase( fwds );
295        }
296}
297
298ast::UnionDecl const * LinkTypesCore::previsit( ast::UnionDecl const * decl ) {
299        enterNamespace();
300        return renameGenericParams( decl );
301}
302
303void LinkTypesCore::postvisit( ast::UnionDecl const * decl ) {
304        if ( !decl->body ) {
305                return;
306        }
307
308        ForwardUnionsType::iterator fwds = forwardUnions.find( decl->name );
309        if ( fwds != forwardUnions.end() ) {
310                for ( auto inst : fwds->second ) {
311                        inst->base = decl;
312                }
313                forwardUnions.erase( fwds );
314        }
315}
316
317ast::TraitDecl const * LinkTypesCore::postvisit( ast::TraitDecl const * decl ) {
318        // There is some overlap with code from decayForallPointers,
319        // perhaps reorganization or shared helper functions are called for.
320        // Move assertions from type parameters into the body of the trait.
321        auto mut = ast::mutate( decl );
322        for ( ast::ptr<ast::TypeDecl> const & td : decl->params ) {
323                auto expanded = expandAssertions( td->assertions );
324                for ( auto declWithType : expanded ) {
325                        mut->members.emplace_back( declWithType.release() );
326                }
327        }
328        return mut;
329}
330
331} // namespace
332
333void linkReferenceToTypes( ast::TranslationUnit & translationUnit ) {
334        ast::Pass<LinkTypesCore>::run( translationUnit );
335}
336
337} // namespace Validate
338
339// Local Variables: //
340// tab-width: 4 //
341// mode: c++ //
342// compile-command: "make install" //
343// End: //
Note: See TracBrowser for help on using the repository browser.