source: src/AST/Expr.cpp@ 17fa94f

stuck-waitfor-destruct
Last change on this file since 17fa94f was 17fa94f, checked in by Andrew Beach <ajbeach@…>, 15 months ago

Reworked some nodes so they can be typed or untyped. This allowed me to remove TranslationDeps as the type information is only needed in the candidate finder, which can easily insert it.

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