source: src/InitTweak/GenInit.cc@ 3a7aa94

Last change on this file since 3a7aa94 was fb4dc28, checked in by Andrew Beach <ajbeach@…>, 2 years ago

Moved new ast code out of one of the old files. The new file may have to change if SymTab is removed entirely, but for now at least, there is a lot less template code in headers.

  • Property mode set to 100644
File size: 28.2 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// GenInit.cc -- Generate initializers, and other stuff.
8//
9// Author : Rob Schluntz
10// Created On : Mon May 18 07:44:20 2015
11// Last Modified By : Andrew Beach
12// Last Modified On : Mon Oct 25 13:53:00 2021
13// Update Count : 186
14//
15#include "GenInit.h"
16
17#include <stddef.h> // for NULL
18#include <algorithm> // for any_of
19#include <cassert> // for assert, strict_dynamic_cast, assertf
20#include <deque>
21#include <iterator> // for back_inserter, inserter, back_inse...
22#include <list> // for _List_iterator, list
23
24#include "AST/Decl.hpp"
25#include "AST/Init.hpp"
26#include "AST/Pass.hpp"
27#include "AST/Node.hpp"
28#include "AST/Stmt.hpp"
29#include "CompilationState.h"
30#include "CodeGen/OperatorTable.h"
31#include "Common/PassVisitor.h" // for PassVisitor, WithGuards, WithShort...
32#include "Common/SemanticError.h" // for SemanticError
33#include "Common/ToString.hpp" // for toCString
34#include "Common/UniqueName.h" // for UniqueName
35#include "Common/utility.h" // for ValueGuard, maybeClone
36#include "GenPoly/GenPoly.h" // for getFunctionType, isPolyType
37#include "GenPoly/ScopedSet.h" // for ScopedSet, ScopedSet<>::const_iter...
38#include "InitTweak.h" // for isConstExpr, InitExpander, checkIn...
39#include "ResolvExpr/Resolver.h"
40#include "SymTab/Autogen.h" // for genImplicitCall
41#include "SymTab/GenImplicitCall.hpp" // for genImplicitCall
42#include "SymTab/Mangler.h" // for Mangler
43#include "SynTree/LinkageSpec.h" // for isOverridable, C
44#include "SynTree/Declaration.h" // for ObjectDecl, DeclarationWithType
45#include "SynTree/Expression.h" // for VariableExpr, UntypedExpr, Address...
46#include "SynTree/Initializer.h" // for ConstructorInit, SingleInit, Initi...
47#include "SynTree/Label.h" // for Label
48#include "SynTree/Mutator.h" // for mutateAll
49#include "SynTree/Statement.h" // for CompoundStmt, ImplicitCtorDtorStmt
50#include "SynTree/Type.h" // for Type, ArrayType, Type::Qualifiers
51#include "SynTree/Visitor.h" // for acceptAll, maybeAccept
52#include "Tuples/Tuples.h" // for maybeImpure
53#include "Validate/FindSpecialDecls.h" // for SizeType
54
55namespace InitTweak {
56 namespace {
57 const std::list<Label> noLabels;
58 const std::list<Expression *> noDesignators;
59 }
60
61 struct ReturnFixer : public WithStmtsToAdd, public WithGuards {
62 /// consistently allocates a temporary variable for the return value
63 /// of a function so that anything which the resolver decides can be constructed
64 /// into the return type of a function can be returned.
65 static void makeReturnTemp( std::list< Declaration * > &translationUnit );
66
67 void premutate( FunctionDecl *functionDecl );
68 void premutate( ReturnStmt * returnStmt );
69
70 protected:
71 FunctionType * ftype = nullptr;
72 std::string funcName;
73 };
74
75 struct CtorDtor : public WithGuards, public WithShortCircuiting, public WithVisitorRef<CtorDtor> {
76 /// create constructor and destructor statements for object declarations.
77 /// the actual call statements will be added in after the resolver has run
78 /// so that the initializer expression is only removed if a constructor is found
79 /// and the same destructor call is inserted in all of the appropriate locations.
80 static void generateCtorDtor( std::list< Declaration * > &translationUnit );
81
82 void previsit( ObjectDecl * );
83 void previsit( FunctionDecl *functionDecl );
84
85 // should not traverse into any of these declarations to find objects
86 // that need to be constructed or destructed
87 void previsit( StructDecl *aggregateDecl );
88 void previsit( AggregateDecl * ) { visit_children = false; }
89 void previsit( NamedTypeDecl * ) { visit_children = false; }
90 void previsit( FunctionType * ) { visit_children = false; }
91
92 void previsit( CompoundStmt * compoundStmt );
93
94 private:
95 // set of mangled type names for which a constructor or destructor exists in the current scope.
96 // these types require a ConstructorInit node to be generated, anything else is a POD type and thus
97 // should not have a ConstructorInit generated.
98
99 ManagedTypes managedTypes;
100 bool inFunction = false;
101 };
102
103 struct HoistArrayDimension final : public WithDeclsToAdd, public WithShortCircuiting, public WithGuards, public WithIndexer {
104 /// hoist dimension from array types in object declaration so that it uses a single
105 /// const variable of type size_t, so that side effecting array dimensions are only
106 /// computed once.
107 static void hoistArrayDimension( std::list< Declaration * > & translationUnit );
108
109 void premutate( ObjectDecl * objectDecl );
110 DeclarationWithType * postmutate( ObjectDecl * objectDecl );
111 void premutate( FunctionDecl *functionDecl );
112 // should not traverse into any of these declarations to find objects
113 // that need to be constructed or destructed
114 void premutate( AggregateDecl * ) { visit_children = false; }
115 void premutate( NamedTypeDecl * ) { visit_children = false; }
116 void premutate( FunctionType * ) { visit_children = false; }
117
118 // need this so that enumerators are added to the indexer, due to premutate(AggregateDecl *)
119 void premutate( EnumDecl * ) {}
120
121 void hoist( Type * type );
122
123 Type::StorageClasses storageClasses;
124 bool inFunction = false;
125 };
126
127 struct HoistArrayDimension_NoResolve final : public WithDeclsToAdd, public WithShortCircuiting, public WithGuards {
128 /// hoist dimension from array types in object declaration so that it uses a single
129 /// const variable of type size_t, so that side effecting array dimensions are only
130 /// computed once.
131 static void hoistArrayDimension( std::list< Declaration * > & translationUnit );
132
133 void premutate( ObjectDecl * objectDecl );
134 DeclarationWithType * postmutate( ObjectDecl * objectDecl );
135 void premutate( FunctionDecl *functionDecl );
136 // should not traverse into any of these declarations to find objects
137 // that need to be constructed or destructed
138 void premutate( AggregateDecl * ) { visit_children = false; }
139 void premutate( NamedTypeDecl * ) { visit_children = false; }
140 void premutate( FunctionType * ) { visit_children = false; }
141
142 void hoist( Type * type );
143
144 Type::StorageClasses storageClasses;
145 bool inFunction = false;
146 };
147
148 void genInit( std::list< Declaration * > & translationUnit ) {
149 if (!useNewAST) {
150 HoistArrayDimension::hoistArrayDimension( translationUnit );
151 }
152 else {
153 HoistArrayDimension_NoResolve::hoistArrayDimension( translationUnit );
154 }
155 fixReturnStatements( translationUnit );
156
157 if (!useNewAST) {
158 CtorDtor::generateCtorDtor( translationUnit );
159 }
160 }
161
162 void fixReturnStatements( std::list< Declaration * > & translationUnit ) {
163 PassVisitor<ReturnFixer> fixer;
164 mutateAll( translationUnit, fixer );
165 }
166
167 void ReturnFixer::premutate( ReturnStmt *returnStmt ) {
168 std::list< DeclarationWithType * > & returnVals = ftype->get_returnVals();
169 assert( returnVals.size() == 0 || returnVals.size() == 1 );
170 // hands off if the function returns a reference - we don't want to allocate a temporary if a variable's address
171 // is being returned
172 if ( returnStmt->expr && returnVals.size() == 1 && isConstructable( returnVals.front()->get_type() ) ) {
173 // explicitly construct the return value using the return expression and the retVal object
174 assertf( returnVals.front()->name != "", "Function %s has unnamed return value\n", funcName.c_str() );
175
176 ObjectDecl * retVal = strict_dynamic_cast< ObjectDecl * >( returnVals.front() );
177 if ( VariableExpr * varExpr = dynamic_cast< VariableExpr * >( returnStmt->expr ) ) {
178 // return statement has already been mutated - don't need to do it again
179 if ( varExpr->var == retVal ) return;
180 }
181 Statement * stmt = genCtorDtor( "?{}", retVal, returnStmt->expr );
182 assertf( stmt, "ReturnFixer: genCtorDtor returned nullptr: %s / %s", toString( retVal ).c_str(), toString( returnStmt->expr ).c_str() );
183 stmtsToAddBefore.push_back( stmt );
184
185 // return the retVal object
186 returnStmt->expr = new VariableExpr( returnVals.front() );
187 } // if
188 }
189
190 void ReturnFixer::premutate( FunctionDecl *functionDecl ) {
191 GuardValue( ftype );
192 GuardValue( funcName );
193
194 ftype = functionDecl->type;
195 funcName = functionDecl->name;
196 }
197
198 // precompute array dimension expression, because constructor generation may duplicate it,
199 // which would be incorrect if it is a side-effecting computation.
200 void HoistArrayDimension::hoistArrayDimension( std::list< Declaration * > & translationUnit ) {
201 PassVisitor<HoistArrayDimension> hoister;
202 mutateAll( translationUnit, hoister );
203 }
204
205 void HoistArrayDimension::premutate( ObjectDecl * objectDecl ) {
206 GuardValue( storageClasses );
207 storageClasses = objectDecl->get_storageClasses();
208 }
209
210 DeclarationWithType * HoistArrayDimension::postmutate( ObjectDecl * objectDecl ) {
211 hoist( objectDecl->get_type() );
212 return objectDecl;
213 }
214
215 void HoistArrayDimension::hoist( Type * type ) {
216 // if in function, generate const size_t var
217 static UniqueName dimensionName( "_array_dim" );
218
219 // C doesn't allow variable sized arrays at global scope or for static variables, so don't hoist dimension.
220 if ( ! inFunction ) return;
221 if ( storageClasses.is_static ) return;
222
223 if ( ArrayType * arrayType = dynamic_cast< ArrayType * >( type ) ) {
224 if ( ! arrayType->get_dimension() ) return; // xxx - recursive call to hoist?
225
226 // need to resolve array dimensions in order to accurately determine if constexpr
227 ResolvExpr::findSingleExpression( arrayType->dimension, Validate::SizeType->clone(), indexer );
228 // array is variable-length when the dimension is not constexpr
229 arrayType->isVarLen = ! isConstExpr( arrayType->dimension );
230 // don't need to hoist dimension if it's definitely pure - only need to if there's potential for side effects.
231 // xxx - hoisting has no side effects anyways, so don't skip since we delay resolve
232 // still try to detect constant expressions
233 if ( ! Tuples::maybeImpure( arrayType->dimension ) ) return;
234
235 ObjectDecl * arrayDimension = new ObjectDecl( dimensionName.newName(), storageClasses, LinkageSpec::C, 0, Validate::SizeType->clone(), new SingleInit( arrayType->get_dimension() ) );
236 arrayDimension->get_type()->set_const( true );
237
238 arrayType->set_dimension( new VariableExpr( arrayDimension ) );
239 declsToAddBefore.push_back( arrayDimension );
240
241 hoist( arrayType->get_base() );
242 return;
243 }
244 }
245
246 void HoistArrayDimension::premutate( FunctionDecl * ) {
247 GuardValue( inFunction );
248 inFunction = true;
249 }
250
251 // precompute array dimension expression, because constructor generation may duplicate it,
252 // which would be incorrect if it is a side-effecting computation.
253 void HoistArrayDimension_NoResolve::hoistArrayDimension( std::list< Declaration * > & translationUnit ) {
254 PassVisitor<HoistArrayDimension_NoResolve> hoister;
255 mutateAll( translationUnit, hoister );
256 }
257
258 void HoistArrayDimension_NoResolve::premutate( ObjectDecl * objectDecl ) {
259 GuardValue( storageClasses );
260 storageClasses = objectDecl->get_storageClasses();
261 }
262
263 DeclarationWithType * HoistArrayDimension_NoResolve::postmutate( ObjectDecl * objectDecl ) {
264 hoist( objectDecl->get_type() );
265 return objectDecl;
266 }
267
268 void HoistArrayDimension_NoResolve::hoist( Type * type ) {
269 // if in function, generate const size_t var
270 static UniqueName dimensionName( "_array_dim" );
271
272 // C doesn't allow variable sized arrays at global scope or for static variables, so don't hoist dimension.
273 if ( ! inFunction ) return;
274 if ( storageClasses.is_static ) return;
275
276 if ( ArrayType * arrayType = dynamic_cast< ArrayType * >( type ) ) {
277 if ( ! arrayType->get_dimension() ) return; // xxx - recursive call to hoist?
278 // don't need to hoist dimension if it's definitely pure - only need to if there's potential for side effects.
279 // xxx - hoisting has no side effects anyways, so don't skip since we delay resolve
280 // still try to detect constant expressions
281 if ( ! Tuples::maybeImpure( arrayType->dimension ) ) return;
282
283 ObjectDecl * arrayDimension = new ObjectDecl( dimensionName.newName(), storageClasses, LinkageSpec::C, 0, Validate::SizeType->clone(), new SingleInit( arrayType->get_dimension() ) );
284 arrayDimension->get_type()->set_const( true );
285
286 arrayType->set_dimension( new VariableExpr( arrayDimension ) );
287 declsToAddBefore.push_back( arrayDimension );
288
289 hoist( arrayType->get_base() );
290 return;
291 }
292 }
293
294 void HoistArrayDimension_NoResolve::premutate( FunctionDecl * ) {
295 GuardValue( inFunction );
296 inFunction = true;
297 }
298
299namespace {
300
301# warning Remove the _New suffix after the conversion is complete.
302 struct HoistArrayDimension_NoResolve_New final :
303 public ast::WithDeclsToAdd<>, public ast::WithShortCircuiting,
304 public ast::WithGuards, public ast::WithConstTranslationUnit,
305 public ast::WithVisitorRef<HoistArrayDimension_NoResolve_New> {
306 void previsit( const ast::ObjectDecl * decl );
307 const ast::DeclWithType * postvisit( const ast::ObjectDecl * decl );
308 // Do not look for objects inside there declarations (and type).
309 void previsit( const ast::AggregateDecl * ) { visit_children = false; }
310 void previsit( const ast::NamedTypeDecl * ) { visit_children = false; }
311 void previsit( const ast::FunctionType * ) { visit_children = false; }
312
313 const ast::Type * hoist( const ast::Type * type );
314
315 ast::Storage::Classes storageClasses;
316 };
317
318 void HoistArrayDimension_NoResolve_New::previsit(
319 const ast::ObjectDecl * decl ) {
320 GuardValue( storageClasses ) = decl->storage;
321 }
322
323 const ast::DeclWithType * HoistArrayDimension_NoResolve_New::postvisit(
324 const ast::ObjectDecl * objectDecl ) {
325 return mutate_field( objectDecl, &ast::ObjectDecl::type,
326 hoist( objectDecl->type ) );
327 }
328
329 const ast::Type * HoistArrayDimension_NoResolve_New::hoist(
330 const ast::Type * type ) {
331 static UniqueName dimensionName( "_array_dim" );
332
333 if ( !isInFunction() || storageClasses.is_static ) {
334 return type;
335 }
336
337 if ( auto arrayType = dynamic_cast< const ast::ArrayType * >( type ) ) {
338 if ( nullptr == arrayType->dimension ) {
339 return type;
340 }
341
342 if ( !Tuples::maybeImpure( arrayType->dimension ) ) {
343 return type;
344 }
345
346 ast::ptr<ast::Type> dimType = transUnit().global.sizeType;
347 assert( dimType );
348 add_qualifiers( dimType, ast::CV::Qualifiers( ast::CV::Const ) );
349
350 ast::ObjectDecl * arrayDimension = new ast::ObjectDecl(
351 arrayType->dimension->location,
352 dimensionName.newName(),
353 dimType,
354 new ast::SingleInit(
355 arrayType->dimension->location,
356 arrayType->dimension
357 )
358 );
359
360 ast::ArrayType * mutType = ast::mutate( arrayType );
361 mutType->dimension = new ast::VariableExpr(
362 arrayDimension->location, arrayDimension );
363 declsToAddBefore.push_back( arrayDimension );
364
365 mutType->base = hoist( mutType->base );
366 return mutType;
367 }
368 return type;
369 }
370
371 struct ReturnFixer_New final :
372 public ast::WithStmtsToAdd<>, ast::WithGuards, ast::WithShortCircuiting {
373 void previsit( const ast::FunctionDecl * decl );
374 const ast::ReturnStmt * previsit( const ast::ReturnStmt * stmt );
375 private:
376 const ast::FunctionDecl * funcDecl = nullptr;
377 };
378
379 void ReturnFixer_New::previsit( const ast::FunctionDecl * decl ) {
380 if (decl->linkage == ast::Linkage::Intrinsic) visit_children = false;
381 GuardValue( funcDecl ) = decl;
382 }
383
384 const ast::ReturnStmt * ReturnFixer_New::previsit(
385 const ast::ReturnStmt * stmt ) {
386 auto & returns = funcDecl->returns;
387 assert( returns.size() < 2 );
388 // Hands off if the function returns a reference.
389 // Don't allocate a temporary if the address is returned.
390 if ( stmt->expr && 1 == returns.size() ) {
391 ast::ptr<ast::DeclWithType> retDecl = returns.front();
392 if ( isConstructable( retDecl->get_type() ) ) {
393 // Explicitly construct the return value using the return
394 // expression and the retVal object.
395 assertf( "" != retDecl->name,
396 "Function %s has unnamed return value.\n",
397 funcDecl->name.c_str() );
398
399 auto retVal = retDecl.strict_as<ast::ObjectDecl>();
400 if ( auto varExpr = stmt->expr.as<ast::VariableExpr>() ) {
401 // Check if the return statement is already set up.
402 if ( varExpr->var == retVal ) return stmt;
403 }
404 ast::ptr<ast::Stmt> ctorStmt = genCtorDtor(
405 retVal->location, "?{}", retVal, stmt->expr );
406 assertf( ctorStmt,
407 "ReturnFixer: genCtorDtor returned nullptr: %s / %s",
408 toString( retVal ).c_str(),
409 toString( stmt->expr ).c_str() );
410 stmtsToAddBefore.push_back( ctorStmt );
411
412 // Return the retVal object.
413 ast::ReturnStmt * mutStmt = ast::mutate( stmt );
414 mutStmt->expr = new ast::VariableExpr(
415 stmt->location, retDecl );
416 return mutStmt;
417 }
418 }
419 return stmt;
420 }
421
422} // namespace
423
424 void genInit( ast::TranslationUnit & transUnit ) {
425 ast::Pass<HoistArrayDimension_NoResolve_New>::run( transUnit );
426 ast::Pass<ReturnFixer_New>::run( transUnit );
427 }
428
429 void fixReturnStatements( ast::TranslationUnit & transUnit ) {
430 ast::Pass<ReturnFixer_New>::run( transUnit );
431 }
432
433 void CtorDtor::generateCtorDtor( std::list< Declaration * > & translationUnit ) {
434 PassVisitor<CtorDtor> ctordtor;
435 acceptAll( translationUnit, ctordtor );
436 }
437
438 bool ManagedTypes::isManaged( Type * type ) const {
439 // references are never constructed
440 if ( dynamic_cast< ReferenceType * >( type ) ) return false;
441 // need to clear and reset qualifiers when determining if a type is managed
442 ValueGuard< Type::Qualifiers > qualifiers( type->get_qualifiers() );
443 type->get_qualifiers() = Type::Qualifiers();
444 if ( TupleType * tupleType = dynamic_cast< TupleType * > ( type ) ) {
445 // tuple is also managed if any of its components are managed
446 if ( std::any_of( tupleType->types.begin(), tupleType->types.end(), [&](Type * type) { return isManaged( type ); }) ) {
447 return true;
448 }
449 }
450 // a type is managed if it appears in the map of known managed types, or if it contains any polymorphism (is a type variable or generic type containing a type variable)
451 return managedTypes.find( SymTab::Mangler::mangleConcrete( type ) ) != managedTypes.end() || GenPoly::isPolyType( type );
452 }
453
454 bool ManagedTypes::isManaged( ObjectDecl * objDecl ) const {
455 Type * type = objDecl->get_type();
456 while ( ArrayType * at = dynamic_cast< ArrayType * >( type ) ) {
457 // must always construct VLAs with an initializer, since this is an error in C
458 if ( at->isVarLen && objDecl->init ) return true;
459 type = at->get_base();
460 }
461 return isManaged( type );
462 }
463
464 // why is this not just on FunctionDecl?
465 void ManagedTypes::handleDWT( DeclarationWithType * dwt ) {
466 // if this function is a user-defined constructor or destructor, mark down the type as "managed"
467 if ( ! LinkageSpec::isOverridable( dwt->get_linkage() ) && CodeGen::isCtorDtor( dwt->get_name() ) ) {
468 std::list< DeclarationWithType * > & params = GenPoly::getFunctionType( dwt->get_type() )->get_parameters();
469 assert( ! params.empty() );
470 Type * type = InitTweak::getPointerBase( params.front()->get_type() );
471 assert( type );
472 managedTypes.insert( SymTab::Mangler::mangleConcrete( type ) );
473 }
474 }
475
476 void ManagedTypes::handleStruct( StructDecl * aggregateDecl ) {
477 // don't construct members, but need to take note if there is a managed member,
478 // because that means that this type is also managed
479 for ( Declaration * member : aggregateDecl->get_members() ) {
480 if ( ObjectDecl * field = dynamic_cast< ObjectDecl * >( member ) ) {
481 if ( isManaged( field ) ) {
482 // generic parameters should not play a role in determining whether a generic type is constructed - construct all generic types, so that
483 // polymorphic constructors make generic types managed types
484 StructInstType inst( Type::Qualifiers(), aggregateDecl );
485 managedTypes.insert( SymTab::Mangler::mangleConcrete( &inst ) );
486 break;
487 }
488 }
489 }
490 }
491
492 void ManagedTypes::beginScope() { managedTypes.beginScope(); }
493 void ManagedTypes::endScope() { managedTypes.endScope(); }
494
495 bool ManagedTypes_new::isManaged( const ast::Type * type ) const {
496 // references are never constructed
497 if ( dynamic_cast< const ast::ReferenceType * >( type ) ) return false;
498 if ( auto tupleType = dynamic_cast< const ast::TupleType * > ( type ) ) {
499 // tuple is also managed if any of its components are managed
500 for (auto & component : tupleType->types) {
501 if (isManaged(component)) return true;
502 }
503 }
504 // need to clear and reset qualifiers when determining if a type is managed
505 // ValueGuard< Type::Qualifiers > qualifiers( type->get_qualifiers() );
506 auto tmp = shallowCopy(type);
507 tmp->qualifiers = {};
508 // delete tmp at return
509 ast::ptr<ast::Type> guard = tmp;
510 // a type is managed if it appears in the map of known managed types, or if it contains any polymorphism (is a type variable or generic type containing a type variable)
511 return managedTypes.find( Mangle::mangle( tmp, {Mangle::NoOverrideable | Mangle::NoGenericParams | Mangle::Type} ) ) != managedTypes.end() || GenPoly::isPolyType( tmp );
512 }
513
514 bool ManagedTypes_new::isManaged( const ast::ObjectDecl * objDecl ) const {
515 const ast::Type * type = objDecl->type;
516 while ( auto at = dynamic_cast< const ast::ArrayType * >( type ) ) {
517 // must always construct VLAs with an initializer, since this is an error in C
518 if ( at->isVarLen && objDecl->init ) return true;
519 type = at->base;
520 }
521 return isManaged( type );
522 }
523
524 void ManagedTypes_new::handleDWT( const ast::DeclWithType * dwt ) {
525 // if this function is a user-defined constructor or destructor, mark down the type as "managed"
526 if ( ! dwt->linkage.is_overrideable && CodeGen::isCtorDtor( dwt->name ) ) {
527 auto & params = GenPoly::getFunctionType( dwt->get_type())->params;
528 assert( ! params.empty() );
529 // Type * type = InitTweak::getPointerBase( params.front() );
530 // assert( type );
531 managedTypes.insert( Mangle::mangle( params.front(), {Mangle::NoOverrideable | Mangle::NoGenericParams | Mangle::Type} ) );
532 }
533 }
534
535 void ManagedTypes_new::handleStruct( const ast::StructDecl * aggregateDecl ) {
536 // don't construct members, but need to take note if there is a managed member,
537 // because that means that this type is also managed
538 for ( auto & member : aggregateDecl->members ) {
539 if ( auto field = member.as<ast::ObjectDecl>() ) {
540 if ( isManaged( field ) ) {
541 // generic parameters should not play a role in determining whether a generic type is constructed - construct all generic types, so that
542 // polymorphic constructors make generic types managed types
543 ast::StructInstType inst( aggregateDecl );
544 managedTypes.insert( Mangle::mangle( &inst, {Mangle::NoOverrideable | Mangle::NoGenericParams | Mangle::Type} ) );
545 break;
546 }
547 }
548 }
549 }
550
551 void ManagedTypes_new::beginScope() { managedTypes.beginScope(); }
552 void ManagedTypes_new::endScope() { managedTypes.endScope(); }
553
554 ImplicitCtorDtorStmt * genCtorDtor( const std::string & fname, ObjectDecl * objDecl, Expression * arg ) {
555 // call into genImplicitCall from Autogen.h to generate calls to ctor/dtor
556 assertf( objDecl, "genCtorDtor passed null objDecl" );
557 std::list< Statement * > stmts;
558 InitExpander_old srcParam( maybeClone( arg ) );
559 SymTab::genImplicitCall( srcParam, new VariableExpr( objDecl ), fname, back_inserter( stmts ), objDecl );
560 assert( stmts.size() <= 1 );
561 return stmts.size() == 1 ? strict_dynamic_cast< ImplicitCtorDtorStmt * >( stmts.front() ) : nullptr;
562
563 }
564
565 ast::ptr<ast::Stmt> genCtorDtor (const CodeLocation & loc, const std::string & fname, const ast::ObjectDecl * objDecl, const ast::Expr * arg) {
566 assertf(objDecl, "genCtorDtor passed null objDecl");
567 InitExpander_new srcParam(arg);
568 return SymTab::genImplicitCall(srcParam, new ast::VariableExpr(loc, objDecl), loc, fname, objDecl);
569 }
570
571 ConstructorInit * genCtorInit( ObjectDecl * objDecl ) {
572 // call into genImplicitCall from Autogen.h to generate calls to ctor/dtor
573 // for each constructable object
574 std::list< Statement * > ctor;
575 std::list< Statement * > dtor;
576
577 InitExpander_old srcParam( objDecl->get_init() );
578 InitExpander_old nullParam( (Initializer *)NULL );
579 SymTab::genImplicitCall( srcParam, new VariableExpr( objDecl ), "?{}", back_inserter( ctor ), objDecl );
580 SymTab::genImplicitCall( nullParam, new VariableExpr( objDecl ), "^?{}", front_inserter( dtor ), objDecl, false );
581
582 // Currently genImplicitCall produces a single Statement - a CompoundStmt
583 // which wraps everything that needs to happen. As such, it's technically
584 // possible to use a Statement ** in the above calls, but this is inherently
585 // unsafe, so instead we take the slightly less efficient route, but will be
586 // immediately informed if somehow the above assumption is broken. In this case,
587 // we could always wrap the list of statements at this point with a CompoundStmt,
588 // but it seems reasonable at the moment for this to be done by genImplicitCall
589 // itself. It is possible that genImplicitCall produces no statements (e.g. if
590 // an array type does not have a dimension). In this case, it's fine to ignore
591 // the object for the purposes of construction.
592 assert( ctor.size() == dtor.size() && ctor.size() <= 1 );
593 if ( ctor.size() == 1 ) {
594 // need to remember init expression, in case no ctors exist
595 // if ctor does exist, want to use ctor expression instead of init
596 // push this decision to the resolver
597 assert( dynamic_cast< ImplicitCtorDtorStmt * > ( ctor.front() ) && dynamic_cast< ImplicitCtorDtorStmt * > ( dtor.front() ) );
598 return new ConstructorInit( ctor.front(), dtor.front(), objDecl->get_init() );
599 }
600 return nullptr;
601 }
602
603 void CtorDtor::previsit( ObjectDecl * objDecl ) {
604 managedTypes.handleDWT( objDecl );
605 // hands off if @=, extern, builtin, etc.
606 // even if unmanaged, try to construct global or static if initializer is not constexpr, since this is not legal C
607 if ( tryConstruct( objDecl ) && ( managedTypes.isManaged( objDecl ) || ((! inFunction || objDecl->get_storageClasses().is_static ) && ! isConstExpr( objDecl->get_init() ) ) ) ) {
608 // constructed objects cannot be designated
609 if ( isDesignated( objDecl->get_init() ) ) SemanticError( objDecl, "Cannot include designations in the initializer for a managed Object. If this is really what you want, then initialize with @=.\n" );
610 // constructed objects should not have initializers nested too deeply
611 if ( ! checkInitDepth( objDecl ) ) SemanticError( objDecl, "Managed object's initializer is too deep " );
612
613 objDecl->set_init( genCtorInit( objDecl ) );
614 }
615 }
616
617 void CtorDtor::previsit( FunctionDecl *functionDecl ) {
618 visit_children = false; // do not try and construct parameters or forall parameters
619 GuardValue( inFunction );
620 inFunction = true;
621
622 managedTypes.handleDWT( functionDecl );
623
624 GuardScope( managedTypes );
625 // go through assertions and recursively add seen ctor/dtors
626 for ( auto & tyDecl : functionDecl->get_functionType()->get_forall() ) {
627 for ( DeclarationWithType *& assertion : tyDecl->get_assertions() ) {
628 managedTypes.handleDWT( assertion );
629 }
630 }
631
632 maybeAccept( functionDecl->get_statements(), *visitor );
633 }
634
635 void CtorDtor::previsit( StructDecl *aggregateDecl ) {
636 visit_children = false; // do not try to construct and destruct aggregate members
637
638 managedTypes.handleStruct( aggregateDecl );
639 }
640
641 void CtorDtor::previsit( CompoundStmt * ) {
642 GuardScope( managedTypes );
643 }
644
645ast::ConstructorInit * genCtorInit( const CodeLocation & loc, const ast::ObjectDecl * objDecl ) {
646 // call into genImplicitCall from Autogen.h to generate calls to ctor/dtor for each
647 // constructable object
648 InitExpander_new srcParam{ objDecl->init }, nullParam{ (const ast::Init *)nullptr };
649 ast::ptr< ast::Expr > dstParam = new ast::VariableExpr(loc, objDecl);
650
651 ast::ptr< ast::Stmt > ctor = SymTab::genImplicitCall(
652 srcParam, dstParam, loc, "?{}", objDecl );
653 ast::ptr< ast::Stmt > dtor = SymTab::genImplicitCall(
654 nullParam, dstParam, loc, "^?{}", objDecl,
655 SymTab::LoopBackward );
656
657 // check that either both ctor and dtor are present, or neither
658 assert( (bool)ctor == (bool)dtor );
659
660 if ( ctor ) {
661 // need to remember init expression, in case no ctors exist. If ctor does exist, want to
662 // use ctor expression instead of init.
663 ctor.strict_as< ast::ImplicitCtorDtorStmt >();
664 dtor.strict_as< ast::ImplicitCtorDtorStmt >();
665
666 return new ast::ConstructorInit{ loc, ctor, dtor, objDecl->init };
667 }
668
669 return nullptr;
670}
671
672} // namespace InitTweak
673
674// Local Variables: //
675// tab-width: 4 //
676// mode: c++ //
677// compile-command: "make install" //
678// End: //
Note: See TracBrowser for help on using the repository browser.