source: src/AST/Type.hpp @ 123e8b9

Last change on this file since 123e8b9 was fc1a3e2, checked in by Andrew Beach <ajbeach@…>, 3 months ago

Style update. Focused on indentation and trailing whitespace.

  • Property mode set to 100644
File size: 17.3 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// Type.hpp --
8//
9// Author           : Aaron B. Moss
10// Created On       : Thu May 9 10:00:00 2019
11// Last Modified By : Andrew Beach
12// Last Modified On : Thu Apr  6 15:58:00 2023
13// Update Count     : 9
14//
15
16#pragma once
17
18#include <cassert>
19#include <cstddef>           // for nullptr_t
20#include <cstdint>           // for uintptr_t
21#include <utility>           // for move
22#include <vector>
23
24#include "BasicKind.hpp"     // for BasicKind
25#include "CVQualifiers.hpp"
26#include "Decl.hpp"          // for AggregateDecl subclasses
27#include "Fwd.hpp"
28#include "Node.hpp"          // for Node, ptr, ptr_base
29#include "Visitor.hpp"
30
31// Must be included in *all* AST classes; should be #undef'd at the end of the file
32#define MUTATE_FRIEND \
33        template<typename node_t> friend node_t * mutate(const node_t * node); \
34        template<typename node_t> friend node_t * shallowCopy(const node_t * node);
35
36namespace ast {
37
38class Type : public Node {
39public:
40        CV::Qualifiers qualifiers;
41        std::vector<ptr<Attribute>> attributes;
42
43        Type( CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} )
44        : qualifiers(q), attributes(std::move(as)) {}
45
46        bool is_const() const { return qualifiers.is_const; }
47        bool is_volatile() const { return qualifiers.is_volatile; }
48        bool is_restrict() const { return qualifiers.is_restrict; }
49        bool is_mutex() const { return qualifiers.is_mutex; }
50        bool is_atomic() const { return qualifiers.is_atomic; }
51
52        Type * set_const( bool v ) { qualifiers.is_const = v; return this; }
53        Type * set_volatile( bool v ) { qualifiers.is_volatile = v; return this; }
54        Type * set_restrict( bool v ) { qualifiers.is_restrict = v; return this; }
55        Type * set_mutex( bool v ) { qualifiers.is_mutex = v; return this; }
56        Type * set_atomic( bool v ) { qualifiers.is_atomic = v; return this; }
57
58        /// How many elemental types are represented by this type
59        virtual unsigned size() const { return 1; }
60        /// Is this a void type?
61        virtual bool isVoid() const { return size() == 0; }
62        /// Get the i'th component of this type
63        virtual const Type * getComponent( unsigned i ) const;
64
65        /// type without outer pointers and arrays
66        const Type * stripDeclarator() const;
67        /// type without outer references
68        const Type * stripReferences() const;
69        /// number of reference occuring consecutively on the outermost layer of this type
70        /// (i.e. do not count references nested within other types)
71        virtual unsigned referenceDepth() const { return 0; }
72        /// true iff type is complete type (i.e. compiler knows the size, alignment, and layout)
73        virtual bool isComplete() const { return true; }
74
75        virtual const Type * accept( Visitor & v ) const override = 0;
76private:
77        virtual Type * clone() const override = 0;
78        MUTATE_FRIEND
79};
80
81/// Clear/reset the qualifiers on this type, cloning only if necessary
82template< enum Node::ref_type ref_t >
83void reset_qualifiers( ptr_base< Type, ref_t > & p, CV::Qualifiers q = {} ) {
84        if ( p->qualifiers != q ) p.get_and_mutate()->qualifiers = q;
85}
86
87/// Add the specified qualifiers to this type, cloning only if necessary
88template< enum Node::ref_type ref_t >
89void add_qualifiers( ptr_base< Type, ref_t > & p, CV::Qualifiers q ) {
90        if ( ( p->qualifiers & q ) != q ) p.get_and_mutate()->qualifiers |= q;
91}
92
93/// Remove the specified qualifiers from this type, cloning only if necessary
94template< enum Node::ref_type ref_t >
95void remove_qualifiers( ptr_base< Type, ref_t > & p, CV::Qualifiers q ) {
96        if ( ( p->qualifiers & q ) != 0 ) p.get_and_mutate()->qualifiers -= q;
97}
98
99/// `void`
100class VoidType final : public Type {
101public:
102        VoidType( CV::Qualifiers q = {} ) : Type( q ) {}
103
104        unsigned size() const override { return 0; }
105        bool isVoid() const override { return true; }
106        bool isComplete() const override { return false; }
107
108        const Type * accept( Visitor & v ) const override { return v.visit( this ); }
109private:
110        VoidType * clone() const override { return new VoidType{ *this }; }
111        MUTATE_FRIEND
112};
113
114/// Built-in arithmetic type
115class BasicType final : public Type {
116public:
117        BasicKind kind;
118
119        /// string names of basic types; generated to match with Kind
120        static const char *typeNames[];
121
122        BasicType( BasicKind k, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} )
123        : Type(q, std::move(as)), kind(k) {}
124
125        /// Check if this type represents an integer type
126        bool isInteger() const { return kind <= MAX_INTEGER_TYPE; }
127
128        const Type * accept( Visitor & v ) const override { return v.visit( this ); }
129private:
130        BasicType * clone() const override { return new BasicType{ *this }; }
131        MUTATE_FRIEND
132};
133
134/// Pointer/array variable length?
135enum LengthFlag { FixedLen, VariableLen };
136
137/// Pointer/array static dimension?
138enum DimensionFlag { DynamicDim, StaticDim };
139
140/// Pointer type `T*`
141class PointerType final : public Type {
142public:
143        ptr<Type> base;
144
145        // In C99, pointer types can be qualified in many ways, e.g. `int a[ static 3 ]`
146        ptr<Expr> dimension;
147        LengthFlag isVarLen = FixedLen;
148        DimensionFlag isStatic = DynamicDim;
149
150        PointerType( const Type * b, CV::Qualifiers q = {} ) : Type(q), base(b), dimension() {}
151        PointerType( const Type * b, const Expr * d, LengthFlag vl, DimensionFlag s,
152                CV::Qualifiers q = {} ) : Type(q), base(b), dimension(d), isVarLen(vl), isStatic(s) {}
153
154        // true if this pointer is actually an array
155        bool isArray() const { return isVarLen || isStatic || dimension; }
156
157        bool isComplete() const override { return ! isVarLen; }
158
159        const Type * accept( Visitor & v ) const override { return v.visit( this ); }
160private:
161        PointerType * clone() const override { return new PointerType{ *this }; }
162        MUTATE_FRIEND
163};
164
165/// Array type `T[]`
166class ArrayType final : public Type {
167public:
168        ptr<Type> base;
169        ptr<Expr> dimension;
170        LengthFlag isVarLen;
171        DimensionFlag isStatic;
172
173        ArrayType( const Type * b, const Expr * d, LengthFlag vl, DimensionFlag s,
174                CV::Qualifiers q = {} ) : Type(q), base(b), dimension(d), isVarLen(vl), isStatic(s) {}
175
176        // array types are complete if they have a dimension expression or are
177        // VLAs ('*' in parameter declaration), and incomplete otherwise.
178        // See 6.7.6.2
179        bool isComplete() const override { return dimension || isVarLen; }
180
181        const Type * accept( Visitor & v ) const override { return v.visit( this ); }
182private:
183        ArrayType * clone() const override { return new ArrayType{ *this }; }
184        MUTATE_FRIEND
185};
186
187/// Reference type `T&`
188class ReferenceType final : public Type {
189public:
190        ptr<Type> base;
191
192        ReferenceType( const Type * b, CV::Qualifiers q = {} ) : Type(q), base(b) {}
193
194        unsigned referenceDepth() const override { return base->referenceDepth() + 1; }
195
196        // Since reference types act like value types, their size is the size of the base.
197        // This makes it simple to cast the empty tuple to a reference type, since casts that increase
198        // the number of values are disallowed.
199        unsigned size() const override { return base->size(); }
200
201        const Type * accept( Visitor & v ) const override { return v.visit( this ); }
202private:
203        ReferenceType * clone() const override { return new ReferenceType{ *this }; }
204        MUTATE_FRIEND
205};
206
207/// Qualified type `P.C`
208class QualifiedType final : public Type {
209public:
210        ptr<Type> parent;
211        ptr<Type> child;
212
213        QualifiedType( const Type * p, const Type * c, CV::Qualifiers q = {} )
214        : Type(q), parent(p), child(c) {}
215
216        const Type * accept( Visitor & v ) const override { return v.visit( this ); }
217private:
218        QualifiedType * clone() const override { return new QualifiedType{ *this }; }
219        MUTATE_FRIEND
220};
221
222/// Type of a function `[R1, R2](*)(P1, P2, P3)`
223class FunctionType final : public Type {
224public:
225        using ForallList = std::vector<ptr<TypeInstType>>;
226        using AssertionList = std::vector<ptr<VariableExpr>>;
227        ForallList forall;
228        AssertionList assertions;
229
230        std::vector<ptr<Type>> returns;
231        std::vector<ptr<Type>> params;
232
233        /// Does the function accept a variable number of arguments following the arguments specified
234        /// in the parameters list.
235        /// This could be because of
236        /// - an ellipsis in a prototype declaration
237        /// - an unprototyped declaration
238        ArgumentFlag isVarArgs;
239
240        FunctionType( ArgumentFlag va = FixedArgs, CV::Qualifiers q = {} )
241        : Type(q), returns(), params(), isVarArgs(va) {}
242
243        FunctionType( const FunctionType & o ) = default;
244
245        /// true if either the parameters or return values contain a tttype
246        bool isTtype() const;
247        /// true if function parameters are unconstrained by prototype
248        bool isUnprototyped() const { return isVarArgs && params.size() == 0; }
249
250        const Type * accept( Visitor & v ) const override { return v.visit( this ); }
251private:
252        FunctionType * clone() const override { return new FunctionType{ *this }; }
253        MUTATE_FRIEND
254};
255
256/// base class for types that refer to types declared elsewhere (aggregates and typedefs)
257class BaseInstType : public Type {
258public:
259        std::vector<ptr<Expr>> params;
260        std::string name;
261        bool hoistType = false;
262
263        BaseInstType(
264                const std::string& n, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} )
265        : Type(q, std::move(as)), params(), name(n) {}
266
267        BaseInstType(
268                const std::string& n, std::vector<ptr<Expr>> && params,
269                CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} )
270        : Type(q, std::move(as)), params(std::move(params)), name(n) {}
271
272        BaseInstType( const BaseInstType & o ) = default;
273
274        /// Gets aggregate declaration this type refers to
275        virtual const AggregateDecl * aggr() const = 0;
276        /// Looks up member declarations with given name
277        std::vector<readonly<Decl>> lookup( const std::string & name ) const;
278
279private:
280        virtual BaseInstType * clone() const override = 0;
281        MUTATE_FRIEND
282};
283
284// Common implementation for the SUE instance types. Not to be used directly.
285template<typename decl_t>
286class SueInstType final : public BaseInstType {
287public:
288        using base_type = decl_t;
289        readonly<decl_t> base;
290
291        SueInstType(
292                const std::string& n, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} )
293        : BaseInstType( n, q, std::move(as) ), base() {}
294
295        SueInstType(
296                const base_type * b, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} );
297
298        SueInstType(
299                const base_type * b, std::vector<ptr<Expr>> && params,
300                CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} );
301
302        bool isComplete() const override;
303
304        const decl_t * aggr() const override { return base; }
305
306        const Type * accept( Visitor & v ) const override { return v.visit( this ); }
307private:
308        SueInstType<decl_t> * clone() const override { return new SueInstType<decl_t>{ *this }; }
309        MUTATE_FRIEND
310};
311
312/// An instance of a struct type.
313using StructInstType = SueInstType<StructDecl>;
314
315/// An instance of a union type.
316using UnionInstType = SueInstType<UnionDecl>;
317
318/// An instance of an enum type.
319using EnumInstType = SueInstType<EnumDecl>;
320
321class EnumAttrType final : public Type {
322public:
323        readonly<EnumInstType> instance;
324        EnumAttribute attr;
325        const Type * accept( Visitor & v ) const override { return v.visit( this ); }
326        EnumAttrType( const EnumInstType * instance, EnumAttribute attr = EnumAttribute::Posn )
327                : instance(instance), attr(attr) {}
328
329        bool match( const ast::EnumAttrType * other) const {
330                return instance->base->name == other->instance->base->name && attr == other->attr;
331        }
332private:
333        EnumAttrType * clone() const override { return new EnumAttrType{ *this }; }
334        MUTATE_FRIEND
335};
336
337/// An instance of a trait type.
338class TraitInstType final : public BaseInstType {
339public:
340        readonly<TraitDecl> base;
341
342        TraitInstType(
343                const std::string& n, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} )
344        : BaseInstType( n, q, std::move(as) ), base() {}
345
346        TraitInstType(
347                const TraitDecl * b, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} );
348
349        // not meaningful for TraitInstType
350        bool isComplete() const override { assert(false); }
351
352        const TraitDecl * aggr() const override { return base; }
353
354        const Type * accept( Visitor & v ) const override { return v.visit( this ); }
355private:
356        TraitInstType * clone() const override { return new TraitInstType{ *this }; }
357        MUTATE_FRIEND
358};
359
360struct TypeEnvKey;
361
362/// instance of named type alias (typedef or variable)
363class TypeInstType final : public BaseInstType {
364public:
365        readonly<TypeDecl> base;
366        // previously from renameTyVars; now directly use integer fields instead of synthesized strings
367        // a nonzero value of formal_usage indicates a formal type (only used in function type)
368        // a zero value of formal_usage indicates an actual type (referenced inside body of parametric structs and functions)
369        TypeDecl::Kind kind;
370        int formal_usage = 0;
371        int expr_id = 0;
372
373        bool operator==(const TypeInstType & other) const;
374
375        TypeInstType(
376                const std::string& n, const TypeDecl * b, CV::Qualifiers q = {},
377                std::vector<ptr<Attribute>> && as = {} )
378        : BaseInstType( n, q, std::move(as) ), base( b ), kind( b->kind ) {}
379
380        TypeInstType( const TypeDecl * b,
381                CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} );
382
383        TypeInstType( const std::string& n, TypeDecl::Kind k, CV::Qualifiers q = {},
384                std::vector<ptr<Attribute>> && as = {} )
385        : BaseInstType( n, q, std::move(as) ), base(), kind( k ) {}
386
387        TypeInstType( const TypeInstType & o ) = default;
388
389        explicit TypeInstType( const TypeEnvKey & key );
390
391        /// sets `base`, updating `kind` correctly
392        void set_base( const TypeDecl * );
393
394        bool isComplete() const override;
395
396        // not meaningful for TypeInstType
397        const AggregateDecl * aggr() const override { assert(false); }
398
399        const Type * accept( Visitor & v ) const override { return v.visit( this ); }
400
401        std::string typeString() const {
402                if (formal_usage > 0) return std::string("_") + std::to_string(formal_usage) + "_" + std::to_string(expr_id) + "_" + name;
403                else return name;
404        }
405private:
406        TypeInstType * clone() const override { return new TypeInstType{ *this }; }
407        MUTATE_FRIEND
408};
409
410/// Compact representation of TypeInstType used for map lookups.
411struct TypeEnvKey {
412        const TypeDecl * base = nullptr;
413        int formal_usage = 0;
414        int expr_id = 0;
415
416        TypeEnvKey() = default;
417        TypeEnvKey(const TypeDecl * base, int formal_usage = 0, int expr_id = 0)
418        : base(base), formal_usage(formal_usage), expr_id(expr_id) {}
419        TypeEnvKey(const TypeInstType & inst)
420        : base(inst.base), formal_usage(inst.formal_usage), expr_id(inst.expr_id) {}
421        std::string typeString() const;
422        bool operator==(const TypeEnvKey & other) const;
423        bool operator<(const TypeEnvKey & other) const;
424        operator bool() {return base;}
425};
426
427
428/// tuple type e.g. `[int, char]`
429class TupleType final : public Type {
430public:
431        std::vector<ptr<Type>> types;
432
433        TupleType( std::vector<ptr<Type>> && ts, CV::Qualifiers q = {} );
434
435        // collection simulation
436        using iterator = std::vector<ptr<Type>>::const_iterator;
437        iterator begin() const { return types.begin(); }
438        iterator end() const { return types.end(); }
439
440        unsigned size() const override { return types.size(); }
441
442        const Type * getComponent( unsigned i ) const override {
443                assertf( i < size(), "TupleType::getComponent: index %d must be less than size %d",
444                        i, size() );
445                return *(begin()+i);
446        }
447
448        const Type * accept( Visitor & v ) const override { return v.visit( this ); }
449private:
450        TupleType * clone() const override { return new TupleType{ *this }; }
451        MUTATE_FRIEND
452};
453
454/// Type of unresolved `typeof()` expression
455class TypeofType : public Type {
456public:
457        ptr<Expr> expr;
458        enum Kind { Typeof, Basetypeof } kind;
459
460        TypeofType( const Expr * e, Kind k = Typeof, CV::Qualifiers q = {} )
461        : Type(q), expr(e), kind(k) {}
462
463        const Type * accept( Visitor & v ) const override { return v.visit( this ); }
464private:
465        TypeofType * clone() const override { return new TypeofType{ *this }; }
466        MUTATE_FRIEND
467};
468
469/// Virtual Table Type `vtable(T)`
470class VTableType final : public Type {
471public:
472        ptr<Type> base;
473
474        VTableType( const Type * b, CV::Qualifiers q = {} ) : Type(q), base(b) {}
475
476        const Type * accept( Visitor & v ) const override { return v.visit( this ); }
477private:
478        VTableType * clone() const override { return new VTableType{ *this }; }
479        MUTATE_FRIEND
480};
481
482/// GCC built-in varargs type
483class VarArgsType final : public Type {
484public:
485        VarArgsType( CV::Qualifiers q = {} ) : Type( q ) {}
486
487        const Type * accept( Visitor & v ) const override { return v.visit( this ); }
488private:
489        VarArgsType * clone() const override { return new VarArgsType{ *this }; }
490        MUTATE_FRIEND
491};
492
493/// Type of zero constant `0`
494class ZeroType final : public Type {
495public:
496        ZeroType( CV::Qualifiers q = {} ) : Type( q ) {}
497
498        const Type * accept( Visitor & v ) const override { return v.visit( this ); }
499private:
500        ZeroType * clone() const override { return new ZeroType{ *this }; }
501        MUTATE_FRIEND
502};
503
504/// Type of one constant `1`
505class OneType final : public Type {
506public:
507        OneType( CV::Qualifiers q = {} ) : Type( q ) {}
508
509        const Type * accept( Visitor & v ) const override { return v.visit( this ); }
510private:
511        OneType * clone() const override { return new OneType{ *this }; }
512        MUTATE_FRIEND
513};
514
515/// Parent type for scope-qualified types at global scope
516class GlobalScopeType final : public Type {
517public:
518        GlobalScopeType() : Type() {}
519
520        const Type * accept( Visitor & v ) const override { return v.visit( this ); }
521private:
522        GlobalScopeType * clone() const override { return new GlobalScopeType{ *this }; }
523        MUTATE_FRIEND
524};
525
526bool isUnboundType(const Type * type);
527
528}
529
530namespace std {
531        template<>
532        struct hash<typename ast::TypeEnvKey> {
533                size_t operator() (const ast::TypeEnvKey & x) const {
534                        const size_t p = 1000007;
535                        size_t res = reinterpret_cast<size_t>(x.base);
536                        res = p * res + x.formal_usage;
537                        res = p * res + x.expr_id;
538                        return res;
539                }
540        };
541}
542
543#undef MUTATE_FRIEND
544
545// Local Variables: //
546// tab-width: 4 //
547// mode: c++ //
548// compile-command: "make install" //
549// End: //
Note: See TracBrowser for help on using the repository browser.