source: src/InitTweak/InitTweak.cc @ fd236ed

ADTaaron-thesisarm-ehast-experimentalcleanup-dtorsdeferred_resndemanglerenumforall-pointer-decayjacob/cs343-translationjenkins-sandboxnew-astnew-ast-unique-exprnew-envno_listpersistent-indexerpthread-emulationqualifiedEnumresolv-newwith_gc
Last change on this file since fd236ed was fd236ed, checked in by Rob Schluntz <rschlunt@…>, 7 years ago

Convert HasDesignations? to PassVisitor?

  • Property mode set to 100644
File size: 25.1 KB
Line 
1#include <algorithm>               // for find, all_of
2#include <cassert>                 // for assertf, assert, strict_dynamic_cast
3#include <iostream>                // for ostream, cerr, endl
4#include <iterator>                // for back_insert_iterator, back_inserter
5#include <memory>                  // for __shared_ptr
6
7#include "Common/PassVisitor.h"
8#include "Common/SemanticError.h"  // for SemanticError
9#include "Common/UniqueName.h"     // for UniqueName
10#include "Common/utility.h"        // for toString, deleteAll, maybeClone
11#include "GenPoly/GenPoly.h"       // for getFunctionType
12#include "InitTweak.h"
13#include "Parser/LinkageSpec.h"    // for Spec, isBuiltin, Intrinsic
14#include "ResolvExpr/typeops.h"    // for typesCompatibleIgnoreQualifiers
15#include "SymTab/Autogen.h"
16#include "SymTab/Indexer.h"        // for Indexer
17#include "SynTree/Attribute.h"     // for Attribute
18#include "SynTree/Constant.h"      // for Constant
19#include "SynTree/Declaration.h"   // for ObjectDecl, DeclarationWithType
20#include "SynTree/Expression.h"    // for Expression, UntypedExpr, Applicati...
21#include "SynTree/Initializer.h"   // for Initializer, ListInit, Designation
22#include "SynTree/Label.h"         // for Label
23#include "SynTree/Statement.h"     // for CompoundStmt, ExprStmt, BranchStmt
24#include "SynTree/Type.h"          // for FunctionType, ArrayType, PointerType
25#include "SynTree/Visitor.h"       // for Visitor, maybeAccept
26#include "Tuples/Tuples.h"         // for Tuples::isTtype
27
28class UntypedValofExpr;
29
30namespace InitTweak {
31        namespace {
32                class HasDesignations : public WithShortCircuiting {
33                public:
34                        bool hasDesignations = false;
35
36                        void previsit( BaseSyntaxNode * ) {
37                                // short circuit if we already know there are designations
38                                if ( hasDesignations ) visit_children = false;
39                        }
40
41                        void previsit( Designation * des ) {
42                                // short circuit if we already know there are designations
43                                if ( hasDesignations ) visit_children = false;
44                                else if ( ! des->get_designators().empty() ) {
45                                        hasDesignations = true;
46                                        visit_children = false;
47                                }
48                        }
49                };
50
51                class InitDepthChecker : public Visitor {
52                public:
53                        bool depthOkay = true;
54                        Type * type;
55                        int curDepth = 0, maxDepth = 0;
56                        InitDepthChecker( Type * type ) : type( type ) {
57                                Type * t = type;
58                                while ( ArrayType * at = dynamic_cast< ArrayType * >( t ) ) {
59                                        maxDepth++;
60                                        t = at->get_base();
61                                }
62                                maxDepth++;
63                        }
64                        virtual void visit( ListInit * listInit ) {
65                                curDepth++;
66                                if ( curDepth > maxDepth ) depthOkay = false;
67                                Visitor::visit( listInit );
68                                curDepth--;
69                        }
70                };
71
72                class InitFlattener : public Visitor {
73                        public:
74                        virtual void visit( SingleInit * singleInit );
75                        virtual void visit( ListInit * listInit );
76                        std::list< Expression * > argList;
77                };
78
79                void InitFlattener::visit( SingleInit * singleInit ) {
80                        argList.push_back( singleInit->get_value()->clone() );
81                }
82
83                void InitFlattener::visit( ListInit * listInit ) {
84                        // flatten nested list inits
85                        std::list<Initializer*>::iterator it = listInit->begin();
86                        for ( ; it != listInit->end(); ++it ) {
87                                (*it)->accept( *this );
88                        }
89                }
90        }
91
92        std::list< Expression * > makeInitList( Initializer * init ) {
93                InitFlattener flattener;
94                maybeAccept( init, flattener );
95                return flattener.argList;
96        }
97
98        bool isDesignated( Initializer * init ) {
99                PassVisitor<HasDesignations> finder;
100                maybeAccept( init, finder );
101                return finder.pass.hasDesignations;
102        }
103
104        bool checkInitDepth( ObjectDecl * objDecl ) {
105                InitDepthChecker checker( objDecl->get_type() );
106                maybeAccept( objDecl->get_init(), checker );
107                return checker.depthOkay;
108        }
109
110        class InitExpander::ExpanderImpl {
111        public:
112                virtual ~ExpanderImpl() = default;
113                virtual std::list< Expression * > next( std::list< Expression * > & indices ) = 0;
114                virtual Statement * buildListInit( UntypedExpr * callExpr, std::list< Expression * > & indices ) = 0;
115        };
116
117        class InitImpl : public InitExpander::ExpanderImpl {
118        public:
119                InitImpl( Initializer * init ) : init( init ) {}
120                virtual ~InitImpl() = default;
121
122                virtual std::list< Expression * > next( __attribute((unused)) std::list< Expression * > & indices ) {
123                        // this is wrong, but just a placeholder for now
124                        // if ( ! flattened ) flatten( indices );
125                        // return ! inits.empty() ? makeInitList( inits.front() ) : std::list< Expression * >();
126                        return makeInitList( init );
127                }
128
129                virtual Statement * buildListInit( UntypedExpr * callExpr, std::list< Expression * > & indices );
130        private:
131                Initializer * init;
132        };
133
134        class ExprImpl : public InitExpander::ExpanderImpl {
135        public:
136                ExprImpl( Expression * expr ) : arg( expr ) {}
137                virtual ~ExprImpl() { delete arg; }
138
139                virtual std::list< Expression * > next( std::list< Expression * > & indices ) {
140                        std::list< Expression * > ret;
141                        Expression * expr = maybeClone( arg );
142                        if ( expr ) {
143                                for ( std::list< Expression * >::reverse_iterator it = indices.rbegin(); it != indices.rend(); ++it ) {
144                                        // go through indices and layer on subscript exprs ?[?]
145                                        ++it;
146                                        UntypedExpr * subscriptExpr = new UntypedExpr( new NameExpr( "?[?]") );
147                                        subscriptExpr->get_args().push_back( expr );
148                                        subscriptExpr->get_args().push_back( (*it)->clone() );
149                                        expr = subscriptExpr;
150                                }
151                                ret.push_back( expr );
152                        }
153                        return ret;
154                }
155
156                virtual Statement * buildListInit( UntypedExpr * callExpr, std::list< Expression * > & indices );
157        private:
158                Expression * arg;
159        };
160
161        InitExpander::InitExpander( Initializer * init ) : expander( new InitImpl( init ) ) {}
162
163        InitExpander::InitExpander( Expression * expr ) : expander( new ExprImpl( expr ) ) {}
164
165        std::list< Expression * > InitExpander::operator*() {
166                return cur;
167        }
168
169        InitExpander & InitExpander::operator++() {
170                cur = expander->next( indices );
171                return *this;
172        }
173
174        // use array indices list to build switch statement
175        void InitExpander::addArrayIndex( Expression * index, Expression * dimension ) {
176                indices.push_back( index );
177                indices.push_back( dimension );
178        }
179
180        void InitExpander::clearArrayIndices() {
181                deleteAll( indices );
182                indices.clear();
183        }
184
185        bool InitExpander::addReference() {
186                bool added = false;
187                for ( Expression *& expr : cur ) {
188                        expr = new AddressExpr( expr );
189                        added = true;
190                }
191                return added;
192        }
193
194        namespace {
195                /// given index i, dimension d, initializer init, and callExpr f, generates
196                ///   if (i < d) f(..., init)
197                ///   ++i;
198                /// so that only elements within the range of the array are constructed
199                template< typename OutIterator >
200                void buildCallExpr( UntypedExpr * callExpr, Expression * index, Expression * dimension, Initializer * init, OutIterator out ) {
201                        UntypedExpr * cond = new UntypedExpr( new NameExpr( "?<?") );
202                        cond->get_args().push_back( index->clone() );
203                        cond->get_args().push_back( dimension->clone() );
204
205                        std::list< Expression * > args = makeInitList( init );
206                        callExpr->get_args().splice( callExpr->get_args().end(), args );
207
208                        *out++ = new IfStmt( cond, new ExprStmt( callExpr ), nullptr );
209
210                        UntypedExpr * increment = new UntypedExpr( new NameExpr( "++?" ) );
211                        increment->get_args().push_back( index->clone() );
212                        *out++ = new ExprStmt( increment );
213                }
214
215                template< typename OutIterator >
216                void build( UntypedExpr * callExpr, InitExpander::IndexList::iterator idx, InitExpander::IndexList::iterator idxEnd, Initializer * init, OutIterator out ) {
217                        if ( idx == idxEnd ) return;
218                        Expression * index = *idx++;
219                        assert( idx != idxEnd );
220                        Expression * dimension = *idx++;
221
222                        // xxx - may want to eventually issue a warning here if we can detect
223                        // that the number of elements exceeds to dimension of the array
224                        if ( idx == idxEnd ) {
225                                if ( ListInit * listInit = dynamic_cast< ListInit * >( init ) ) {
226                                        for ( Initializer * init : *listInit ) {
227                                                buildCallExpr( callExpr->clone(), index, dimension, init, out );
228                                        }
229                                } else {
230                                        buildCallExpr( callExpr->clone(), index, dimension, init, out );
231                                }
232                        } else {
233                                std::list< Statement * > branches;
234
235                                unsigned long cond = 0;
236                                ListInit * listInit = dynamic_cast< ListInit * >( init );
237                                if ( ! listInit ) {
238                                        // xxx - this shouldn't be an error, but need a way to
239                                        // terminate without creating output, so should catch this error
240                                        throw SemanticError( "unbalanced list initializers" );
241                                }
242
243                                static UniqueName targetLabel( "L__autogen__" );
244                                Label switchLabel( targetLabel.newName(), 0, std::list< Attribute * >{ new Attribute("unused") } );
245                                for ( Initializer * init : *listInit ) {
246                                        Expression * condition;
247                                        // check for designations
248                                        // if ( init-> ) {
249                                                condition = new ConstantExpr( Constant::from_ulong( cond ) );
250                                                ++cond;
251                                        // } else {
252                                        //      condition = // ... take designation
253                                        //      cond = // ... take designation+1
254                                        // }
255                                        std::list< Statement * > stmts;
256                                        build( callExpr, idx, idxEnd, init, back_inserter( stmts ) );
257                                        stmts.push_back( new BranchStmt( switchLabel, BranchStmt::Break ) );
258                                        CaseStmt * caseStmt = new CaseStmt( condition, stmts );
259                                        branches.push_back( caseStmt );
260                                }
261                                *out++ = new SwitchStmt( index->clone(), branches );
262                                *out++ = new NullStmt( { switchLabel } );
263                        }
264                }
265        }
266
267        // if array came with an initializer list: initialize each element
268        // may have more initializers than elements in the array - need to check at each index that
269        // we haven't exceeded size.
270        // may have fewer initializers than elements in the array - need to default construct
271        // remaining elements.
272        // To accomplish this, generate switch statement, consuming all of expander's elements
273        Statement * InitImpl::buildListInit( UntypedExpr * dst, std::list< Expression * > & indices ) {
274                if ( ! init ) return nullptr;
275                CompoundStmt * block = new CompoundStmt();
276                build( dst, indices.begin(), indices.end(), init, back_inserter( block->get_kids() ) );
277                if ( block->get_kids().empty() ) {
278                        delete block;
279                        return nullptr;
280                } else {
281                        init = nullptr; // init was consumed in creating the list init
282                        return block;
283                }
284        }
285
286        Statement * ExprImpl::buildListInit( UntypedExpr *, std::list< Expression * > & ) {
287                return nullptr;
288        }
289
290        Statement * InitExpander::buildListInit( UntypedExpr * dst ) {
291                return expander->buildListInit( dst, indices );
292        }
293
294        Type * getTypeofThis( FunctionType * ftype ) {
295                assertf( ftype, "getTypeofThis: nullptr ftype" );
296                ObjectDecl * thisParam = getParamThis( ftype );
297                ReferenceType * refType = strict_dynamic_cast< ReferenceType * >( thisParam->type );
298                return refType->base;
299        }
300
301        ObjectDecl * getParamThis( FunctionType * ftype ) {
302                assertf( ftype, "getParamThis: nullptr ftype" );
303                auto & params = ftype->parameters;
304                assertf( ! params.empty(), "getParamThis: ftype with 0 parameters: %s", toString( ftype ).c_str() );
305                return strict_dynamic_cast< ObjectDecl * >( params.front() );
306        }
307
308        bool tryConstruct( DeclarationWithType * dwt ) {
309                ObjectDecl * objDecl = dynamic_cast< ObjectDecl * >( dwt );
310                if ( ! objDecl ) return false;
311                return ! LinkageSpec::isBuiltin( objDecl->get_linkage() ) &&
312                        (objDecl->get_init() == nullptr ||
313                                ( objDecl->get_init() != nullptr && objDecl->get_init()->get_maybeConstructed() ))
314                        && ! objDecl->get_storageClasses().is_extern
315                        && isConstructable( objDecl->type );
316        }
317
318        bool isConstructable( Type * type ) {
319                return ! dynamic_cast< VarArgsType * >( type ) && ! dynamic_cast< ReferenceType * >( type ) && ! dynamic_cast< FunctionType * >( type ) && ! Tuples::isTtype( type );
320        }
321
322        class CallFinder : public Visitor {
323        public:
324                typedef Visitor Parent;
325                CallFinder( const std::list< std::string > & names ) : names( names ) {}
326
327                virtual void visit( ApplicationExpr * appExpr ) {
328                        handleCallExpr( appExpr );
329                }
330
331                virtual void visit( UntypedExpr * untypedExpr ) {
332                        handleCallExpr( untypedExpr );
333                }
334
335                std::list< Expression * > * matches;
336        private:
337                const std::list< std::string > names;
338
339                template< typename CallExpr >
340                void handleCallExpr( CallExpr * expr ) {
341                        Parent::visit( expr );
342                        std::string fname = getFunctionName( expr );
343                        if ( std::find( names.begin(), names.end(), fname ) != names.end() ) {
344                                matches->push_back( expr );
345                        }
346                }
347        };
348
349        void collectCtorDtorCalls( Statement * stmt, std::list< Expression * > & matches ) {
350                static CallFinder finder( std::list< std::string >{ "?{}", "^?{}" } );
351                finder.matches = &matches;
352                maybeAccept( stmt, finder );
353        }
354
355        Expression * getCtorDtorCall( Statement * stmt ) {
356                std::list< Expression * > matches;
357                collectCtorDtorCalls( stmt, matches );
358                assert( matches.size() <= 1 );
359                return matches.size() == 1 ? matches.front() : nullptr;
360        }
361
362        namespace {
363                DeclarationWithType * getCalledFunction( Expression * expr );
364
365                template<typename CallExpr>
366                DeclarationWithType * handleDerefCalledFunction( CallExpr * expr ) {
367                        // (*f)(x) => should get "f"
368                        std::string name = getFunctionName( expr );
369                        assertf( name == "*?", "Unexpected untyped expression: %s", name.c_str() );
370                        assertf( ! expr->get_args().empty(), "Cannot get called function from dereference with no arguments" );
371                        return getCalledFunction( expr->get_args().front() );
372                }
373
374                DeclarationWithType * getCalledFunction( Expression * expr ) {
375                        assert( expr );
376                        if ( VariableExpr * varExpr = dynamic_cast< VariableExpr * >( expr ) ) {
377                                return varExpr->var;
378                        } else if ( MemberExpr * memberExpr = dynamic_cast< MemberExpr * >( expr ) ) {
379                                return memberExpr->member;
380                        } else if ( CastExpr * castExpr = dynamic_cast< CastExpr * >( expr ) ) {
381                                return getCalledFunction( castExpr->arg );
382                        } else if ( UntypedExpr * untypedExpr = dynamic_cast< UntypedExpr * >( expr ) ) {
383                                return handleDerefCalledFunction( untypedExpr );
384                        } else if ( ApplicationExpr * appExpr = dynamic_cast< ApplicationExpr * > ( expr ) ) {
385                                return handleDerefCalledFunction( appExpr );
386                        } else if ( AddressExpr * addrExpr = dynamic_cast< AddressExpr * >( expr ) ) {
387                                return getCalledFunction( addrExpr->arg );
388                        } else if ( CommaExpr * commaExpr = dynamic_cast< CommaExpr * >( expr ) ) {
389                                return getCalledFunction( commaExpr->arg2 );
390                        }
391                        return nullptr;
392                }
393        }
394
395        DeclarationWithType * getFunction( Expression * expr ) {
396                if ( ApplicationExpr * appExpr = dynamic_cast< ApplicationExpr * >( expr ) ) {
397                        return getCalledFunction( appExpr->get_function() );
398                } else if ( UntypedExpr * untyped = dynamic_cast< UntypedExpr * > ( expr ) ) {
399                        return getCalledFunction( untyped->get_function() );
400                }
401                assertf( false, "getFunction received unknown expression: %s", toString( expr ).c_str() );
402        }
403
404        ApplicationExpr * isIntrinsicCallExpr( Expression * expr ) {
405                ApplicationExpr * appExpr = dynamic_cast< ApplicationExpr * >( expr );
406                if ( ! appExpr ) return nullptr;
407                DeclarationWithType * function = getCalledFunction( appExpr->get_function() );
408                assertf( function, "getCalledFunction returned nullptr: %s", toString( appExpr->get_function() ).c_str() );
409                // check for Intrinsic only - don't want to remove all overridable ctor/dtors because autogenerated ctor/dtor
410                // will call all member dtors, and some members may have a user defined dtor.
411                return function->get_linkage() == LinkageSpec::Intrinsic ? appExpr : nullptr;
412        }
413
414        namespace {
415                template <typename Predicate>
416                bool allofCtorDtor( Statement * stmt, const Predicate & pred ) {
417                        std::list< Expression * > callExprs;
418                        collectCtorDtorCalls( stmt, callExprs );
419                        // if ( callExprs.empty() ) return false; // xxx - do I still need this check?
420                        return std::all_of( callExprs.begin(), callExprs.end(), pred);
421                }
422        }
423
424        bool isIntrinsicSingleArgCallStmt( Statement * stmt ) {
425                return allofCtorDtor( stmt, []( Expression * callExpr ){
426                        if ( ApplicationExpr * appExpr = isIntrinsicCallExpr( callExpr ) ) {
427                                FunctionType *funcType = GenPoly::getFunctionType( appExpr->get_function()->get_result() );
428                                assert( funcType );
429                                return funcType->get_parameters().size() == 1;
430                        }
431                        return false;
432                });
433        }
434
435        bool isIntrinsicCallStmt( Statement * stmt ) {
436                return allofCtorDtor( stmt, []( Expression * callExpr ) {
437                        return isIntrinsicCallExpr( callExpr );
438                });
439        }
440
441        namespace {
442                template<typename CallExpr>
443                Expression *& callArg( CallExpr * callExpr, unsigned int pos ) {
444                        if ( pos >= callExpr->get_args().size() ) assertf( false, "getCallArg for argument that doesn't exist: (%u); %s.", pos, toString( callExpr ).c_str() );
445                        for ( Expression *& arg : callExpr->get_args() ) {
446                                if ( pos == 0 ) return arg;
447                                pos--;
448                        }
449                        assert( false );
450                }
451        }
452
453        Expression *& getCallArg( Expression * callExpr, unsigned int pos ) {
454                if ( ApplicationExpr * appExpr = dynamic_cast< ApplicationExpr * >( callExpr ) ) {
455                        return callArg( appExpr, pos );
456                } else if ( UntypedExpr * untypedExpr = dynamic_cast< UntypedExpr * >( callExpr ) ) {
457                        return callArg( untypedExpr, pos );
458                } else if ( TupleAssignExpr * tupleExpr = dynamic_cast< TupleAssignExpr * > ( callExpr ) ) {
459                        std::list< Statement * > & stmts = tupleExpr->get_stmtExpr()->get_statements()->get_kids();
460                        assertf( ! stmts.empty(), "TupleAssignExpr somehow has no statements." );
461                        ExprStmt * stmt = strict_dynamic_cast< ExprStmt * >( stmts.back() );
462                        TupleExpr * tuple = strict_dynamic_cast< TupleExpr * >( stmt->get_expr() );
463                        assertf( ! tuple->get_exprs().empty(), "TupleAssignExpr somehow has empty tuple expr." );
464                        return getCallArg( tuple->get_exprs().front(), pos );
465                } else if ( ImplicitCopyCtorExpr * copyCtor = dynamic_cast< ImplicitCopyCtorExpr * >( callExpr ) ) {
466                        return getCallArg( copyCtor->callExpr, pos );
467                } else {
468                        assertf( false, "Unexpected expression type passed to getCallArg: %s", toString( callExpr ).c_str() );
469                }
470        }
471
472        namespace {
473                std::string funcName( Expression * func );
474
475                template<typename CallExpr>
476                std::string handleDerefName( CallExpr * expr ) {
477                        // (*f)(x) => should get name "f"
478                        std::string name = getFunctionName( expr );
479                        assertf( name == "*?", "Unexpected untyped expression: %s", name.c_str() );
480                        assertf( ! expr->get_args().empty(), "Cannot get function name from dereference with no arguments" );
481                        return funcName( expr->get_args().front() );
482                }
483
484                std::string funcName( Expression * func ) {
485                        if ( NameExpr * nameExpr = dynamic_cast< NameExpr * >( func ) ) {
486                                return nameExpr->get_name();
487                        } else if ( VariableExpr * varExpr = dynamic_cast< VariableExpr * >( func ) ) {
488                                return varExpr->get_var()->get_name();
489                        }       else if ( CastExpr * castExpr = dynamic_cast< CastExpr * >( func ) ) {
490                                return funcName( castExpr->get_arg() );
491                        } else if ( MemberExpr * memberExpr = dynamic_cast< MemberExpr * >( func ) ) {
492                                return memberExpr->get_member()->get_name();
493                        } else if ( UntypedMemberExpr * memberExpr = dynamic_cast< UntypedMemberExpr * > ( func ) ) {
494                                return funcName( memberExpr->get_member() );
495                        } else if ( UntypedExpr * untypedExpr = dynamic_cast< UntypedExpr * >( func ) ) {
496                                return handleDerefName( untypedExpr );
497                        } else if ( ApplicationExpr * appExpr = dynamic_cast< ApplicationExpr * >( func ) ) {
498                                return handleDerefName( appExpr );
499                        } else if ( ConstructorExpr * ctorExpr = dynamic_cast< ConstructorExpr * >( func ) ) {
500                                return funcName( getCallArg( ctorExpr->get_callExpr(), 0 ) );
501                        } else {
502                                assertf( false, "Unexpected expression type being called as a function in call expression: %s", toString( func ).c_str() );
503                        }
504                }
505        }
506
507        std::string getFunctionName( Expression * expr ) {
508                // there's some unforunate overlap here with getCalledFunction. Ideally this would be able to use getCalledFunction and
509                // return the name of the DeclarationWithType, but this needs to work for NameExpr and UntypedMemberExpr, where getCalledFunction
510                // can't possibly do anything reasonable.
511                if ( ApplicationExpr * appExpr = dynamic_cast< ApplicationExpr * >( expr ) ) {
512                        return funcName( appExpr->get_function() );
513                } else if ( UntypedExpr * untypedExpr = dynamic_cast< UntypedExpr * > ( expr ) ) {
514                        return funcName( untypedExpr->get_function() );
515                } else {
516                        std::cerr << expr << std::endl;
517                        assertf( false, "Unexpected expression type passed to getFunctionName" );
518                }
519        }
520
521        Type * getPointerBase( Type * type ) {
522                if ( PointerType * ptrType = dynamic_cast< PointerType * >( type ) ) {
523                        return ptrType->get_base();
524                } else if ( ArrayType * arrayType = dynamic_cast< ArrayType * >( type ) ) {
525                        return arrayType->get_base();
526                } else if ( ReferenceType * refType = dynamic_cast< ReferenceType * >( type ) ) {
527                        return refType->get_base();
528                } else {
529                        return nullptr;
530                }
531        }
532
533        Type * isPointerType( Type * type ) {
534                if ( getPointerBase( type ) ) return type;
535                else return nullptr;
536        }
537
538        ApplicationExpr * createBitwiseAssignment( Expression * dst, Expression * src ) {
539                static FunctionDecl * assign = nullptr;
540                if ( ! assign ) {
541                        // temporary? Generate a fake assignment operator to represent bitwise assignments.
542                        // This operator could easily exist as a real function, but it's tricky because nothing should resolve to this function.
543                        TypeDecl * td = new TypeDecl( "T", noStorageClasses, nullptr, TypeDecl::Dtype, true );
544                        assign = new FunctionDecl( "?=?", noStorageClasses, LinkageSpec::Intrinsic, SymTab::genAssignType( new TypeInstType( noQualifiers, td->name, td ) ), nullptr );
545                }
546                if ( dynamic_cast< ReferenceType * >( dst->result ) ) {
547                        dst = new AddressExpr( dst );
548                } else {
549                        dst = new CastExpr( dst, new ReferenceType( noQualifiers, dst->result->clone() ) );
550                }
551                if ( dynamic_cast< ReferenceType * >( src->result ) ) {
552                        src = new CastExpr( src, new ReferenceType( noQualifiers, src->result->stripReferences()->clone() ) );
553                }
554                return new ApplicationExpr( VariableExpr::functionPointer( assign ), { dst, src } );
555        }
556
557        class ConstExprChecker : public Visitor {
558        public:
559                ConstExprChecker() : isConstExpr( true ) {}
560
561                using Visitor::visit;
562
563                virtual void visit( ApplicationExpr * ) { isConstExpr = false; }
564                virtual void visit( UntypedExpr * ) { isConstExpr = false; }
565                virtual void visit( NameExpr * ) { isConstExpr = false; }
566                // virtual void visit( CastExpr *castExpr ) { isConstExpr = false; }
567                virtual void visit( AddressExpr *addressExpr ) {
568                        // address of a variable or member expression is constexpr
569                        Expression * arg = addressExpr->get_arg();
570                        if ( ! dynamic_cast< NameExpr * >( arg) && ! dynamic_cast< VariableExpr * >( arg ) && ! dynamic_cast< MemberExpr * >( arg ) && ! dynamic_cast< UntypedMemberExpr * >( arg ) ) isConstExpr = false;
571                }
572                virtual void visit( UntypedMemberExpr * ) { isConstExpr = false; }
573                virtual void visit( MemberExpr * ) { isConstExpr = false; }
574                virtual void visit( VariableExpr * ) { isConstExpr = false; }
575                // these might be okay?
576                // virtual void visit( SizeofExpr *sizeofExpr );
577                // virtual void visit( AlignofExpr *alignofExpr );
578                // virtual void visit( UntypedOffsetofExpr *offsetofExpr );
579                // virtual void visit( OffsetofExpr *offsetofExpr );
580                // virtual void visit( OffsetPackExpr *offsetPackExpr );
581                // virtual void visit( AttrExpr *attrExpr );
582                // virtual void visit( CommaExpr *commaExpr );
583                // virtual void visit( LogicalExpr *logicalExpr );
584                // virtual void visit( ConditionalExpr *conditionalExpr );
585                virtual void visit( TypeExpr * ) { isConstExpr = false; }
586                virtual void visit( AsmExpr * ) { isConstExpr = false; }
587                virtual void visit( UntypedValofExpr * ) { isConstExpr = false; }
588                virtual void visit( CompoundLiteralExpr * ) { isConstExpr = false; }
589                virtual void visit( UntypedTupleExpr * ) { isConstExpr = false; }
590                virtual void visit( TupleExpr * ) { isConstExpr = false; }
591                virtual void visit( TupleAssignExpr * ) { isConstExpr = false; }
592
593                bool isConstExpr;
594        };
595
596        bool isConstExpr( Expression * expr ) {
597                if ( expr ) {
598                        ConstExprChecker checker;
599                        expr->accept( checker );
600                        return checker.isConstExpr;
601                }
602                return true;
603        }
604
605        bool isConstExpr( Initializer * init ) {
606                if ( init ) {
607                        ConstExprChecker checker;
608                        init->accept( checker );
609                        return checker.isConstExpr;
610                } // if
611                // for all intents and purposes, no initializer means const expr
612                return true;
613        }
614
615        bool isConstructor( const std::string & str ) { return str == "?{}"; }
616        bool isDestructor( const std::string & str ) { return str == "^?{}"; }
617        bool isAssignment( const std::string & str ) { return str == "?=?"; }
618        bool isCtorDtor( const std::string & str ) { return isConstructor( str ) || isDestructor( str ); }
619        bool isCtorDtorAssign( const std::string & str ) { return isCtorDtor( str ) || isAssignment( str ); }
620
621        FunctionDecl * isCopyFunction( Declaration * decl, const std::string & fname ) {
622                FunctionDecl * function = dynamic_cast< FunctionDecl * >( decl );
623                if ( ! function ) return nullptr;
624                if ( function->name != fname ) return nullptr;
625                FunctionType * ftype = function->type;
626                if ( ftype->parameters.size() != 2 ) return nullptr;
627
628                Type * t1 = getPointerBase( ftype->get_parameters().front()->get_type() );
629                Type * t2 = ftype->parameters.back()->get_type();
630                assert( t1 );
631
632                if ( ResolvExpr::typesCompatibleIgnoreQualifiers( t1, t2, SymTab::Indexer() ) ) {
633                        return function;
634                } else {
635                        return nullptr;
636                }
637        }
638
639        FunctionDecl * isAssignment( Declaration * decl ) {
640                return isCopyFunction( decl, "?=?" );
641        }
642        FunctionDecl * isDestructor( Declaration * decl ) {
643                if ( isDestructor( decl->get_name() ) ) {
644                        return dynamic_cast< FunctionDecl * >( decl );
645                }
646                return nullptr;
647        }
648        FunctionDecl * isDefaultConstructor( Declaration * decl ) {
649                if ( isConstructor( decl->name ) ) {
650                        if ( FunctionDecl * func = dynamic_cast< FunctionDecl * >( decl ) ) {
651                                if ( func->type->parameters.size() == 1 ) {
652                                        return func;
653                                }
654                        }
655                }
656                return nullptr;
657        }
658        FunctionDecl * isCopyConstructor( Declaration * decl ) {
659                return isCopyFunction( decl, "?{}" );
660        }
661}
Note: See TracBrowser for help on using the repository browser.