source: src/AST/Expr.cpp @ f5dbc8d

Last change on this file since f5dbc8d was b6f2e7ab, checked in by Andrew Beach <ajbeach@…>, 5 weeks ago

Removed SizeofExpr::expr and AlignofExpr::expr, expressions that would be stored there are wrapped in TypeofType? and stored in the type field. Some special cases to hide the typeof in code generation were added. In addition, initializer length is calculated in more cases so that the full type of more arrays is known sooner. Other than that, most of the code changes were just stripping out the conditional code and checks no longer needed. Some tests had to be updated, because the typeof is not hidden in dumps and the resolver replaces known typeof expressions with the type. The extension case caused some concern but it appears that just hides warnings in the expression which no longer exists.

  • Property mode set to 100644
File size: 13.0 KB
RevLine 
[54e41b3]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// Expr.cpp --
8//
9// Author           : Aaron B. Moss
10// Created On       : Wed May 15 17:00:00 2019
[b1f2007]11// Last Modified By : Peter A. Buhr
[e6cf857f]12// Created On       : Wed May 18 13:56:00 2022
[b1f2007]13// Update Count     : 12
[54e41b3]14//
15
16#include "Expr.hpp"
17
18#include <cassert>                 // for strict_dynamic_cast
19#include <string>                  // for to_string
20#include <vector>
21
[2890212]22#include "Copy.hpp"                // for shallowCopy
[d8938622]23#include "GenericSubstitution.hpp"
[e01eb4a]24#include "Inspect.hpp"
[cf32116]25#include "LinkageSpec.hpp"
[9b4f329]26#include "Stmt.hpp"
[54e41b3]27#include "Type.hpp"
[d8938622]28#include "TypeSubstitution.hpp"
[c92bdcc]29#include "Common/Utility.hpp"
30#include "Common/SemanticError.hpp"
31#include "GenPoly/Lvalue.hpp"      // for referencesPermissable
32#include "ResolvExpr/Unify.hpp"    // for extractResultType
33#include "Tuples/Tuples.hpp"       // for makeTupleType
[54e41b3]34
35namespace ast {
36
[cf32116]37namespace {
38        std::set<std::string> const lvalueFunctionNames = {"*?", "?[?]"};
39}
40
41// --- Expr
42bool Expr::get_lvalue() const {
43        return false;
44}
45
[54e41b3]46// --- ApplicationExpr
47
[87701b6]48ApplicationExpr::ApplicationExpr( const CodeLocation & loc, const Expr * f,
49        std::vector<ptr<Expr>> && as )
50: Expr( loc ), func( f ), args( std::move(as) ) {
[54e41b3]51        // ensure that `ApplicationExpr` result type is `FuncExpr`
52        const PointerType * pt = strict_dynamic_cast< const PointerType * >( f->result.get() );
53        const FunctionType * fn = strict_dynamic_cast< const FunctionType * >( pt->base.get() );
54
55        result = ResolvExpr::extractResultType( fn );
56        assert( result );
57}
58
[cf32116]59bool ApplicationExpr::get_lvalue() const {
[e01eb4a]60        if ( const DeclWithType * func = getFunction( this ) ) {
[cf32116]61                return func->linkage == Linkage::Intrinsic && lvalueFunctionNames.count( func->name );
62        }
63        return false;
64}
65
[54e41b3]66// --- UntypedExpr
67
[e6cf857f]68bool UntypedExpr::get_lvalue() const {
[e01eb4a]69        std::string fname = getFunctionName( this );
[e6cf857f]70        return lvalueFunctionNames.count( fname );
71}
72
[490fb92e]73UntypedExpr * UntypedExpr::createDeref( const CodeLocation & loc, const Expr * arg ) {
[54e41b3]74        assert( arg );
75
[e6cf857f]76        UntypedExpr * ret = createCall( loc, "*?", { arg } );
[54e41b3]77        if ( const Type * ty = arg->result ) {
[e01eb4a]78                const Type * base = getPointerBase( ty );
[54e41b3]79                assertf( base, "expected pointer type in dereference (type was %s)", toString( ty ).c_str() );
80
81                if ( GenPoly::referencesPermissable() ) {
82                        // if references are still allowed in the AST, dereference returns a reference
83                        ret->result = new ReferenceType{ base };
84                } else {
[87701b6]85                        // references have been removed, in which case dereference returns an lvalue of the
[54e41b3]86                        // base type
[d76c588]87                        ret->result = base;
[54e41b3]88                }
89        }
90        return ret;
91}
92
[490fb92e]93UntypedExpr * UntypedExpr::createAssign( const CodeLocation & loc, const Expr * lhs, const Expr * rhs ) {
[54e41b3]94        assert( lhs && rhs );
95
[e6cf857f]96        UntypedExpr * ret = createCall( loc, "?=?", { lhs, rhs } );
[54e41b3]97        if ( lhs->result && rhs->result ) {
98                // if both expressions are typed, assumes that this assignment is a C bitwise assignment,
99                // so the result is the type of the RHS
100                ret->result = rhs->result;
101        }
102        return ret;
103}
104
[e6cf857f]105UntypedExpr * UntypedExpr::createCall( const CodeLocation & loc,
106                const std::string & name, std::vector<ptr<Expr>> && args ) {
107        return new UntypedExpr( loc,
108                        new NameExpr( loc, name ), std::move( args ) );
109}
110
[d5631b3]111// --- VariableExpr
112
113VariableExpr::VariableExpr( const CodeLocation & loc )
114: Expr( loc ), var( nullptr ) {}
115
116VariableExpr::VariableExpr( const CodeLocation & loc, const DeclWithType * v )
117: Expr( loc ), var( v ) {
118        assert( var );
119        assert( var->get_type() );
120        result = shallowCopy( var->get_type() );
121}
122
123bool VariableExpr::get_lvalue() const {
124        // It isn't always an lvalue, but it is never an rvalue.
125        return true;
126}
127
128VariableExpr * VariableExpr::functionPointer(
129                const CodeLocation & loc, const FunctionDecl * decl ) {
130        // wrap usually-determined result type in a pointer
131        VariableExpr * funcExpr = new VariableExpr{ loc, decl };
132        funcExpr->result = new PointerType{ funcExpr->result };
133        return funcExpr;
134}
135
[54e41b3]136// --- AddressExpr
137
138// Address expressions are typed based on the following inference rules:
139//    E : lvalue T  &..& (n references)
140//   &E :        T *&..& (n references)
141//
142//    E : T  &..&        (m references)
143//   &E : T *&..&        (m-1 references)
144
145namespace {
146        /// The type of the address of a type.
147        /// Caller is responsible for managing returned memory
[f27331c]148        Type * addrType( const ptr<Type> & type ) {
149                if ( auto refType = type.as< ReferenceType >() ) {
150                        return new ReferenceType( addrType( refType->base ), refType->qualifiers );
[54e41b3]151                } else {
[f27331c]152                        return new PointerType( type );
[54e41b3]153                }
154        }
155
[f27331c]156        /// The type of the address of an expression.
157        /// Caller is responsible for managing returned memory
158        Type * addrExprType( const CodeLocation & loc, const Expr * arg ) {
159                assert( arg );
160                // If the expression's type is unknown, the address type is unknown.
161                if ( nullptr == arg->result ) {
162                        return nullptr;
163                // An lvalue is transformed directly.
164                } else if ( arg->get_lvalue() ) {
165                        return addrType( arg->result );
166                // Strip a layer of reference to "create" an lvalue expression.
167                } else if ( auto refType = arg->result.as< ReferenceType >() ) {
168                        return addrType( refType->base );
[54e41b3]169                } else {
[b1f2007]170                        SemanticError( loc, "Attempt to take address of non-lvalue expression %s",
171                                                   toString( arg->result.get() ).c_str() );
[54e41b3]172                }
173        }
174}
175
[f27331c]176AddressExpr::AddressExpr( const CodeLocation & loc, const Expr * a ) :
177        Expr( loc, addrExprType( loc, a ) ), arg( a )
178{}
179
[54e41b3]180// --- LabelAddressExpr
181
182// label address always has type `void*`
[87701b6]183LabelAddressExpr::LabelAddressExpr( const CodeLocation & loc, Label && a )
[54e41b3]184: Expr( loc, new PointerType{ new VoidType{} } ), arg( a ) {}
185
186// --- CastExpr
187
[46da46b]188CastExpr::CastExpr( const CodeLocation & loc, const Expr * a, GeneratedFlag g, CastKind kind )
189: Expr( loc, new VoidType{} ), arg( a ), isGenerated( g ), kind( kind ) {}
[54e41b3]190
[cf32116]191bool CastExpr::get_lvalue() const {
192        // This is actually wrong by C, but it works with our current set-up.
193        return arg->get_lvalue();
194}
195
[54e41b3]196// --- KeywordCastExpr
197
[312029a]198const char * KeywordCastExpr::targetString() const {
199        return AggregateDecl::aggrString( target );
[54e41b3]200}
201
[cf32116]202// --- UntypedMemberExpr
203
204bool UntypedMemberExpr::get_lvalue() const {
205        return aggregate->get_lvalue();
206}
207
[54e41b3]208// --- MemberExpr
209
210MemberExpr::MemberExpr( const CodeLocation & loc, const DeclWithType * mem, const Expr * agg )
211: Expr( loc ), member( mem ), aggregate( agg ) {
212        assert( member );
213        assert( aggregate );
214        assert( aggregate->result );
215
[3e5dd913]216        result = mem->get_type();
[ae265b55]217
[335f2d8]218        // substitute aggregate generic parameters into member type
[60aaa51d]219        genericSubstitution( aggregate->result ).apply( result );
[3f3bfe5a]220        // ensure appropriate restrictions from aggregate type
221        add_qualifiers( result, aggregate->result->qualifiers );
[54e41b3]222}
223
[cf32116]224bool MemberExpr::get_lvalue() const {
225        // This is actually wrong by C, but it works with our current set-up.
226        return true;
227}
228
[54e41b3]229// --- ConstantExpr
230
231long long int ConstantExpr::intValue() const {
232        if ( const BasicType * bty = result.as< BasicType >() ) {
233                if ( bty->isInteger() ) {
[c36298d]234                        assert(ival);
235                        return ival.value();
[54e41b3]236                }
237        } else if ( result.as< ZeroType >() ) {
238                return 0;
239        } else if ( result.as< OneType >() ) {
240                return 1;
241        }
[b1f2007]242        SemanticError( this->location, "Constant expression of non-integral type %s",
243                                   toString( this ).c_str() );
[54e41b3]244}
245
246ConstantExpr * ConstantExpr::from_bool( const CodeLocation & loc, bool b ) {
[87701b6]247        return new ConstantExpr{
[7a780ad]248                loc, new BasicType{ BasicKind::Bool }, b ? "1" : "0", (unsigned long long)b };
[54e41b3]249}
250
251ConstantExpr * ConstantExpr::from_int( const CodeLocation & loc, int i ) {
[87701b6]252        return new ConstantExpr{
[7a780ad]253                loc, new BasicType{ BasicKind::SignedInt }, std::to_string( i ), (unsigned long long)i };
[54e41b3]254}
255
256ConstantExpr * ConstantExpr::from_ulong( const CodeLocation & loc, unsigned long i ) {
[87701b6]257        return new ConstantExpr{
[7a780ad]258                loc, new BasicType{ BasicKind::LongUnsignedInt }, std::to_string( i ),
[54e41b3]259                (unsigned long long)i };
260}
261
[b91bfde]262ConstantExpr * ConstantExpr::from_string( const CodeLocation & loc, const std::string & str ) {
[c2cf2d0]263        const Type * charType = new BasicType( BasicKind::Char, ast::CV::Const );
[b91bfde]264        // Adjust the length of the string for the terminator.
265        const Expr * strSize = from_ulong( loc, str.size() + 1 );
[6a896b0]266        const Type * strType = new ArrayType( charType, strSize, FixedLen, DynamicDim );
[b91bfde]267        const std::string strValue = "\"" + str + "\"";
268        return new ConstantExpr( loc, strType, strValue, std::nullopt );
269}
270
[54e41b3]271ConstantExpr * ConstantExpr::null( const CodeLocation & loc, const Type * ptrType ) {
272        return new ConstantExpr{
273                loc, ptrType ? ptrType : new PointerType{ new VoidType{} }, "0", (unsigned long long)0 };
274}
275
276// --- SizeofExpr
277
278SizeofExpr::SizeofExpr( const CodeLocation & loc, const Type * t )
[b6f2e7ab]279: Expr( loc, new BasicType{ BasicKind::LongUnsignedInt } ), type( t ) {}
[54e41b3]280
[525f7ad]281// --- CountExpr
282
[0c327ce]283CountExpr::CountExpr( const CodeLocation & loc, const Expr * e )
284: Expr( loc, new BasicType( BasicKind::LongUnsignedInt) ), expr(e), type( nullptr ) {}
285
[525f7ad]286CountExpr::CountExpr( const CodeLocation & loc, const Type * t )
[0c327ce]287: Expr( loc, new BasicType( BasicKind::LongUnsignedInt) ), expr(nullptr), type( t ) {}
[525f7ad]288
[54e41b3]289// --- AlignofExpr
290
291AlignofExpr::AlignofExpr( const CodeLocation & loc, const Type * t )
[b6f2e7ab]292: Expr( loc, new BasicType{ BasicKind::LongUnsignedInt } ), type( t ) {}
[54e41b3]293
294// --- OffsetofExpr
295
296OffsetofExpr::OffsetofExpr( const CodeLocation & loc, const Type * ty, const DeclWithType * mem )
[7a780ad]297: Expr( loc, new BasicType{ BasicKind::LongUnsignedInt } ), type( ty ), member( mem ) {
[54e41b3]298        assert( type );
299        assert( member );
300}
301
302// --- OffsetPackExpr
303
304OffsetPackExpr::OffsetPackExpr( const CodeLocation & loc, const StructInstType * ty )
[87701b6]305: Expr( loc, new ArrayType{
[7a780ad]306        new BasicType{ BasicKind::LongUnsignedInt }, nullptr, FixedLen, DynamicDim }
[54e41b3]307), type( ty ) {
308        assert( type );
309}
310
311// --- LogicalExpr
312
[87701b6]313LogicalExpr::LogicalExpr(
[54e41b3]314        const CodeLocation & loc, const Expr * a1, const Expr * a2, LogicalFlag ia )
[7a780ad]315: Expr( loc, new BasicType{ BasicKind::SignedInt } ), arg1( a1 ), arg2( a2 ), isAnd( ia ) {}
[54e41b3]316
[cf32116]317// --- CommaExpr
318bool CommaExpr::get_lvalue() const {
319        // This is wrong by C, but the current implementation uses it.
320        // (ex: Specialize, Lvalue and Box)
321        return arg2->get_lvalue();
322}
323
[9b4f329]324// --- ConstructorExpr
325
[10a1225]326ConstructorExpr::ConstructorExpr( const CodeLocation & loc, const Expr * call )
[9b4f329]327: Expr( loc ), callExpr( call ) {
[10a1225]328        // allow resolver to type a constructor used as an expression if it has the same type as its
[9b4f329]329        // first argument
330        assert( callExpr );
[e01eb4a]331        const Expr * arg = getCallArg( callExpr, 0 );
[9b4f329]332        assert( arg );
333        result = arg->result;
334}
335
336// --- CompoundLiteralExpr
337
338CompoundLiteralExpr::CompoundLiteralExpr( const CodeLocation & loc, const Type * t, const Init * i )
339: Expr( loc ), init( i ) {
340        assert( t && i );
[d76c588]341        result = t;
[9b4f329]342}
343
[cf32116]344bool CompoundLiteralExpr::get_lvalue() const {
345        return true;
346}
347
[9b4f329]348// --- TupleExpr
349
350TupleExpr::TupleExpr( const CodeLocation & loc, std::vector<ptr<Expr>> && xs )
351: Expr( loc, Tuples::makeTupleType( xs ) ), exprs( xs ) {}
352
353// --- TupleIndexExpr
354
355TupleIndexExpr::TupleIndexExpr( const CodeLocation & loc, const Expr * t, unsigned i )
356: Expr( loc ), tuple( t ), index( i ) {
[10a1225]357        const TupleType * type = strict_dynamic_cast< const TupleType * >( tuple->result.get() );
[9b4f329]358        assertf( type->size() > index, "TupleIndexExpr index out of bounds: tuple size %d, requested "
359                "index %d in expr %s", type->size(), index, toString( tuple ).c_str() );
360        // like MemberExpr, TupleIndexExpr is always an lvalue
[d76c588]361        result = type->types[ index ];
[9b4f329]362}
363
[cf32116]364bool TupleIndexExpr::get_lvalue() const {
365        return tuple->get_lvalue();
366}
367
[9b4f329]368// --- TupleAssignExpr
369
[10a1225]370TupleAssignExpr::TupleAssignExpr(
371        const CodeLocation & loc, std::vector<ptr<Expr>> && assigns,
[9b4f329]372        std::vector<ptr<ObjectDecl>> && tempDecls )
373: Expr( loc, Tuples::makeTupleType( assigns ) ), stmtExpr() {
[10a1225]374        // convert internally into a StmtExpr which contains the declarations and produces the tuple of
[9b4f329]375        // the assignments
376        std::list<ptr<Stmt>> stmts;
377        for ( const ObjectDecl * obj : tempDecls ) {
378                stmts.emplace_back( new DeclStmt{ loc, obj } );
379        }
380        TupleExpr * tupleExpr = new TupleExpr{ loc, std::move(assigns) };
381        assert( tupleExpr->result );
382        stmts.emplace_back( new ExprStmt{ loc, tupleExpr } );
383        stmtExpr = new StmtExpr{ loc, new CompoundStmt{ loc, std::move(stmts) } };
384}
385
386// --- StmtExpr
387
[10a1225]388StmtExpr::StmtExpr( const CodeLocation & loc, const CompoundStmt * ss )
[9b4f329]389: Expr( loc ), stmts( ss ), returnDecls(), dtors() { computeResult(); }
390
391void StmtExpr::computeResult() {
392        assert( stmts );
393        const std::list<ptr<Stmt>> & body = stmts->kids;
394        if ( ! returnDecls.empty() ) {
[10a1225]395                // prioritize return decl for result type, since if a return decl exists, then the StmtExpr
[9b4f329]396                // is currently in an intermediate state where the body will always give a void result type
397                result = returnDecls.front()->get_type();
398        } else if ( ! body.empty() ) {
399                if ( const ExprStmt * exprStmt = body.back().as< ExprStmt >() ) {
400                        result = exprStmt->expr->result;
401                }
402        }
403        // ensure a result type exists
404        if ( ! result ) { result = new VoidType{}; }
405}
406
407// --- UniqueExpr
408
409unsigned long long UniqueExpr::nextId = 0;
410
[10a1225]411UniqueExpr::UniqueExpr( const CodeLocation & loc, const Expr * e, unsigned long long i )
[d76f32c]412: Expr( loc, e->result ), expr( e ), id( i ) {
[9b4f329]413        assert( expr );
[10a1225]414        if ( id == -1ull ) {
415                assert( nextId != -1ull );
[9b4f329]416                id = nextId++;
417        }
[54e41b3]418}
419
[10a1225]420}
421
[54e41b3]422// Local Variables: //
423// tab-width: 4 //
424// mode: c++ //
425// compile-command: "make install" //
[d76f32c]426// End: //
Note: See TracBrowser for help on using the repository browser.