source: src/AST/Expr.cpp@ 2d6add4

Last change on this file since 2d6add4 was b6f2e7ab, checked in by Andrew Beach <ajbeach@…>, 13 months 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.