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
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
[b1f2007d]11// Last Modified By : Peter A. Buhr
[e6cf857f]12// Created On : Wed May 18 13:56:00 2022
[b1f2007d]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 {
[b1f2007d]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 }
[b1f2007d]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.