source: src/AST/Expr.cpp @ f5dbc8d

Last change on this file since f5dbc8d was b6f2e7ab, checked in by Andrew Beach <ajbeach@…>, 39 hours 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
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// Expr.cpp --
8//
9// Author           : Aaron B. Moss
10// Created On       : Wed May 15 17:00:00 2019
11// Last Modified By : Peter A. Buhr
12// Created On       : Wed May 18 13:56:00 2022
13// Update Count     : 12
14//
15
16#include "Expr.hpp"
17
18#include <cassert>                 // for strict_dynamic_cast
19#include <string>                  // for to_string
20#include <vector>
21
22#include "Copy.hpp"                // for shallowCopy
23#include "GenericSubstitution.hpp"
24#include "Inspect.hpp"
25#include "LinkageSpec.hpp"
26#include "Stmt.hpp"
27#include "Type.hpp"
28#include "TypeSubstitution.hpp"
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
34
35namespace ast {
36
37namespace {
38        std::set<std::string> const lvalueFunctionNames = {"*?", "?[?]"};
39}
40
41// --- Expr
42bool Expr::get_lvalue() const {
43        return false;
44}
45
46// --- ApplicationExpr
47
48ApplicationExpr::ApplicationExpr( const CodeLocation & loc, const Expr * f,
49        std::vector<ptr<Expr>> && as )
50: Expr( loc ), func( f ), args( std::move(as) ) {
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
59bool ApplicationExpr::get_lvalue() const {
60        if ( const DeclWithType * func = getFunction( this ) ) {
61                return func->linkage == Linkage::Intrinsic && lvalueFunctionNames.count( func->name );
62        }
63        return false;
64}
65
66// --- UntypedExpr
67
68bool UntypedExpr::get_lvalue() const {
69        std::string fname = getFunctionName( this );
70        return lvalueFunctionNames.count( fname );
71}
72
73UntypedExpr * UntypedExpr::createDeref( const CodeLocation & loc, const Expr * arg ) {
74        assert( arg );
75
76        UntypedExpr * ret = createCall( loc, "*?", { arg } );
77        if ( const Type * ty = arg->result ) {
78                const Type * base = getPointerBase( ty );
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 {
85                        // references have been removed, in which case dereference returns an lvalue of the
86                        // base type
87                        ret->result = base;
88                }
89        }
90        return ret;
91}
92
93UntypedExpr * UntypedExpr::createAssign( const CodeLocation & loc, const Expr * lhs, const Expr * rhs ) {
94        assert( lhs && rhs );
95
96        UntypedExpr * ret = createCall( loc, "?=?", { lhs, rhs } );
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
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
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
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
148        Type * addrType( const ptr<Type> & type ) {
149                if ( auto refType = type.as< ReferenceType >() ) {
150                        return new ReferenceType( addrType( refType->base ), refType->qualifiers );
151                } else {
152                        return new PointerType( type );
153                }
154        }
155
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 );
169                } else {
170                        SemanticError( loc, "Attempt to take address of non-lvalue expression %s",
171                                                   toString( arg->result.get() ).c_str() );
172                }
173        }
174}
175
176AddressExpr::AddressExpr( const CodeLocation & loc, const Expr * a ) :
177        Expr( loc, addrExprType( loc, a ) ), arg( a )
178{}
179
180// --- LabelAddressExpr
181
182// label address always has type `void*`
183LabelAddressExpr::LabelAddressExpr( const CodeLocation & loc, Label && a )
184: Expr( loc, new PointerType{ new VoidType{} } ), arg( a ) {}
185
186// --- CastExpr
187
188CastExpr::CastExpr( const CodeLocation & loc, const Expr * a, GeneratedFlag g, CastKind kind )
189: Expr( loc, new VoidType{} ), arg( a ), isGenerated( g ), kind( kind ) {}
190
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
196// --- KeywordCastExpr
197
198const char * KeywordCastExpr::targetString() const {
199        return AggregateDecl::aggrString( target );
200}
201
202// --- UntypedMemberExpr
203
204bool UntypedMemberExpr::get_lvalue() const {
205        return aggregate->get_lvalue();
206}
207
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
216        result = mem->get_type();
217
218        // substitute aggregate generic parameters into member type
219        genericSubstitution( aggregate->result ).apply( result );
220        // ensure appropriate restrictions from aggregate type
221        add_qualifiers( result, aggregate->result->qualifiers );
222}
223
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
229// --- ConstantExpr
230
231long long int ConstantExpr::intValue() const {
232        if ( const BasicType * bty = result.as< BasicType >() ) {
233                if ( bty->isInteger() ) {
234                        assert(ival);
235                        return ival.value();
236                }
237        } else if ( result.as< ZeroType >() ) {
238                return 0;
239        } else if ( result.as< OneType >() ) {
240                return 1;
241        }
242        SemanticError( this->location, "Constant expression of non-integral type %s",
243                                   toString( this ).c_str() );
244}
245
246ConstantExpr * ConstantExpr::from_bool( const CodeLocation & loc, bool b ) {
247        return new ConstantExpr{
248                loc, new BasicType{ BasicKind::Bool }, b ? "1" : "0", (unsigned long long)b };
249}
250
251ConstantExpr * ConstantExpr::from_int( const CodeLocation & loc, int i ) {
252        return new ConstantExpr{
253                loc, new BasicType{ BasicKind::SignedInt }, std::to_string( i ), (unsigned long long)i };
254}
255
256ConstantExpr * ConstantExpr::from_ulong( const CodeLocation & loc, unsigned long i ) {
257        return new ConstantExpr{
258                loc, new BasicType{ BasicKind::LongUnsignedInt }, std::to_string( i ),
259                (unsigned long long)i };
260}
261
262ConstantExpr * ConstantExpr::from_string( const CodeLocation & loc, const std::string & str ) {
263        const Type * charType = new BasicType( BasicKind::Char, ast::CV::Const );
264        // Adjust the length of the string for the terminator.
265        const Expr * strSize = from_ulong( loc, str.size() + 1 );
266        const Type * strType = new ArrayType( charType, strSize, FixedLen, DynamicDim );
267        const std::string strValue = "\"" + str + "\"";
268        return new ConstantExpr( loc, strType, strValue, std::nullopt );
269}
270
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 )
279: Expr( loc, new BasicType{ BasicKind::LongUnsignedInt } ), type( t ) {}
280
281// --- CountExpr
282
283CountExpr::CountExpr( const CodeLocation & loc, const Expr * e )
284: Expr( loc, new BasicType( BasicKind::LongUnsignedInt) ), expr(e), type( nullptr ) {}
285
286CountExpr::CountExpr( const CodeLocation & loc, const Type * t )
287: Expr( loc, new BasicType( BasicKind::LongUnsignedInt) ), expr(nullptr), type( t ) {}
288
289// --- AlignofExpr
290
291AlignofExpr::AlignofExpr( const CodeLocation & loc, const Type * t )
292: Expr( loc, new BasicType{ BasicKind::LongUnsignedInt } ), type( t ) {}
293
294// --- OffsetofExpr
295
296OffsetofExpr::OffsetofExpr( const CodeLocation & loc, const Type * ty, const DeclWithType * mem )
297: Expr( loc, new BasicType{ BasicKind::LongUnsignedInt } ), type( ty ), member( mem ) {
298        assert( type );
299        assert( member );
300}
301
302// --- OffsetPackExpr
303
304OffsetPackExpr::OffsetPackExpr( const CodeLocation & loc, const StructInstType * ty )
305: Expr( loc, new ArrayType{
306        new BasicType{ BasicKind::LongUnsignedInt }, nullptr, FixedLen, DynamicDim }
307), type( ty ) {
308        assert( type );
309}
310
311// --- LogicalExpr
312
313LogicalExpr::LogicalExpr(
314        const CodeLocation & loc, const Expr * a1, const Expr * a2, LogicalFlag ia )
315: Expr( loc, new BasicType{ BasicKind::SignedInt } ), arg1( a1 ), arg2( a2 ), isAnd( ia ) {}
316
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
324// --- ConstructorExpr
325
326ConstructorExpr::ConstructorExpr( const CodeLocation & loc, const Expr * call )
327: Expr( loc ), callExpr( call ) {
328        // allow resolver to type a constructor used as an expression if it has the same type as its
329        // first argument
330        assert( callExpr );
331        const Expr * arg = getCallArg( callExpr, 0 );
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 );
341        result = t;
342}
343
344bool CompoundLiteralExpr::get_lvalue() const {
345        return true;
346}
347
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 ) {
357        const TupleType * type = strict_dynamic_cast< const TupleType * >( tuple->result.get() );
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
361        result = type->types[ index ];
362}
363
364bool TupleIndexExpr::get_lvalue() const {
365        return tuple->get_lvalue();
366}
367
368// --- TupleAssignExpr
369
370TupleAssignExpr::TupleAssignExpr(
371        const CodeLocation & loc, std::vector<ptr<Expr>> && assigns,
372        std::vector<ptr<ObjectDecl>> && tempDecls )
373: Expr( loc, Tuples::makeTupleType( assigns ) ), stmtExpr() {
374        // convert internally into a StmtExpr which contains the declarations and produces the tuple of
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
388StmtExpr::StmtExpr( const CodeLocation & loc, const CompoundStmt * ss )
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() ) {
395                // prioritize return decl for result type, since if a return decl exists, then the StmtExpr
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
411UniqueExpr::UniqueExpr( const CodeLocation & loc, const Expr * e, unsigned long long i )
412: Expr( loc, e->result ), expr( e ), id( i ) {
413        assert( expr );
414        if ( id == -1ull ) {
415                assert( nextId != -1ull );
416                id = nextId++;
417        }
418}
419
420}
421
422// Local Variables: //
423// tab-width: 4 //
424// mode: c++ //
425// compile-command: "make install" //
426// End: //
Note: See TracBrowser for help on using the repository browser.