source: src/AST/Decl.cpp @ 8f557161

Last change on this file since 8f557161 was 8f557161, checked in by Michael Brooks <mlbrooks@…>, 13 months ago

Clarify and fix accuracy in eval public API, on reporting "unable to evaluate."

While the eval internals always used the flag pair valid and cfavalid almost correctly, the public interface exposed the outcome as a single flag, and the various interpretations of this flag were a mess.

Old cfacc treated sizeof(whatever) in some contexts as "known to be zero," which is wrong.
The generally correct answer, which new cfacc now uses is, "unknown now, but GCC will see it as a fine constant."
New tests/eval.cfa captures this fact: is runnable and would fail on old cfacc; it passes with new cfacc.

  • Property mode set to 100644
File size: 7.5 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// Decl.cpp --
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 May  5 12:10:00 2022
13// Update Count     : 24
14//
15
16#include "Decl.hpp"
17
18#include <cassert>             // for assert, strict_dynamic_cast
19#include <iostream>
20#include <unordered_map>
21
22#include "Common/Eval.h"       // for eval
23
24#include "Fwd.hpp"             // for UniqueId
25#include "Init.hpp"
26#include "Node.hpp"            // for readonly
27#include "Type.hpp"            // for readonly
28#include "Expr.hpp"
29
30namespace ast {
31
32// To canonicalize declarations
33static UniqueId lastUniqueId = 0;
34
35using IdMapType = std::unordered_map< UniqueId, readonly<Decl> >;
36static IdMapType idMap;
37
38void Decl::fixUniqueId() {
39        if ( uniqueId ) return;  // ensure only set once
40        uniqueId = ++lastUniqueId;
41        // The extra readonly pointer is causing some reference counting issues.
42        // idMap[ uniqueId ] = this;
43}
44
45readonly<Decl> Decl::fromId( UniqueId id ) {
46        // Right now this map is always empty, so don't use it.
47        assert( false );
48        IdMapType::const_iterator i = idMap.find( id );
49        if ( i != idMap.end() ) return i->second;
50        return {};
51}
52
53// --- FunctionDecl
54
55FunctionDecl::FunctionDecl( const CodeLocation & loc, const std::string & name,
56        std::vector<ptr<TypeDecl>>&& forall,
57        std::vector<ptr<DeclWithType>>&& params, std::vector<ptr<DeclWithType>>&& returns,
58        CompoundStmt * stmts, Storage::Classes storage, Linkage::Spec linkage,
59        std::vector<ptr<Attribute>>&& attrs, Function::Specs fs, ArgumentFlag isVarArgs )
60: DeclWithType( loc, name, storage, linkage, std::move(attrs), fs ),
61        type_params(std::move(forall)), assertions(),
62        params(std::move(params)), returns(std::move(returns)), stmts( stmts ) {
63        FunctionType * ftype = new FunctionType( isVarArgs );
64        for (auto & param : this->params) {
65                ftype->params.emplace_back(param->get_type());
66        }
67        for (auto & ret : this->returns) {
68                ftype->returns.emplace_back(ret->get_type());
69        }
70        for (auto & tp : this->type_params) {
71                ftype->forall.emplace_back(new TypeInstType(tp));
72                for (auto & ap: tp->assertions) {
73                        ftype->assertions.emplace_back(new VariableExpr(loc, ap));
74                }
75        }
76        this->type = ftype;
77}
78
79FunctionDecl::FunctionDecl( const CodeLocation & location, const std::string & name,
80        std::vector<ptr<TypeDecl>>&& forall, std::vector<ptr<DeclWithType>>&& assertions,
81        std::vector<ptr<DeclWithType>>&& params, std::vector<ptr<DeclWithType>>&& returns,
82        CompoundStmt * stmts, Storage::Classes storage, Linkage::Spec linkage,
83        std::vector<ptr<Attribute>>&& attrs, Function::Specs fs, ArgumentFlag isVarArgs )
84: DeclWithType( location, name, storage, linkage, std::move(attrs), fs ),
85                type_params( std::move( forall) ), assertions( std::move( assertions ) ),
86                params( std::move(params) ), returns( std::move(returns) ),
87                type( nullptr ), stmts( stmts ) {
88        FunctionType * type = new FunctionType( isVarArgs );
89        for ( auto & param : this->params ) {
90                type->params.emplace_back( param->get_type() );
91        }
92        for ( auto & ret : this->returns ) {
93                type->returns.emplace_back( ret->get_type() );
94        }
95        for ( auto & param : this->type_params ) {
96                type->forall.emplace_back( new TypeInstType( param ) );
97        }
98        for ( auto & assertion : this->assertions ) {
99                type->assertions.emplace_back(
100                        new VariableExpr( assertion->location, assertion ) );
101        }
102        this->type = type;
103}
104
105
106const Type * FunctionDecl::get_type() const { return type.get(); }
107void FunctionDecl::set_type( const Type * t ) {
108        type = strict_dynamic_cast< const FunctionType * >( t );
109}
110
111// --- TypeDecl
112
113const char * TypeDecl::typeString() const {
114        static const char * kindNames[] = { "sized data type", "sized data type", "sized object type", "sized function type", "sized tuple type", "sized length value" };
115        static_assert( sizeof(kindNames) / sizeof(kindNames[0]) == TypeDecl::NUMBER_OF_KINDS, "typeString: kindNames is out of sync." );
116        assertf( kind < TypeDecl::NUMBER_OF_KINDS, "TypeDecl kind is out of bounds." );
117        return sized ? kindNames[ kind ] : &kindNames[ kind ][ sizeof("sized") ]; // sizeof includes '\0'
118}
119
120const char * TypeDecl::genTypeString() const {
121        static const char * kindNames[] = { "T &", "T *", "T", "(*)", "T ...", "[T]" };
122        static_assert( sizeof(kindNames) / sizeof(kindNames[0]) == TypeDecl::NUMBER_OF_KINDS, "genTypeString: kindNames is out of sync." );
123        assertf( kind < TypeDecl::NUMBER_OF_KINDS, "TypeDecl kind is out of bounds." );
124        return kindNames[ kind ];
125}
126
127std::ostream & operator<< ( std::ostream & out, const TypeData & data ) {
128        return out << data.kind << ", " << data.isComplete;
129}
130
131// --- AggregateDecl
132
133// These must harmonize with the corresponding AggregateDecl::Aggregate enumerations.
134static const char * aggregateNames[] = { "struct", "union", "enum", "exception", "trait", "generator", "coroutine", "monitor", "thread", "NoAggregateName" };
135
136const char * AggregateDecl::aggrString( AggregateDecl::Aggregate aggr ) {
137        return aggregateNames[aggr];
138}
139
140// --- EnumDecl
141
142bool EnumDecl::valueOf( const Decl * enumerator, long long& value ) const {
143        if ( enumValues.empty() ) {
144                Evaluation crntVal = {0, true, true};  // until expression is given, we know to start counting from 0
145                for ( const Decl * member : members ) {
146                        const ObjectDecl* field = strict_dynamic_cast< const ObjectDecl* >( member );
147                        if ( field->init ) {
148                                const SingleInit * init = strict_dynamic_cast< const SingleInit* >( field->init.get() );
149                                crntVal = eval( init->value );
150                                if ( ! crntVal.isEvaluableInGCC ) {
151                                        SemanticError( init->location, ::toString( "Non-constexpr in initialization of "
152                                                "enumerator: ", field ) );
153                                }
154                        }
155                        if ( enumValues.count( field->name ) != 0 ) {
156                                SemanticError( location, ::toString( "Enum ", name, " has multiple members with the "   "name ", field->name ) );
157                        }
158                        if (crntVal.hasKnownValue) {
159                                enumValues[ field->name ] = crntVal.knownValue;
160                        }
161                        ++crntVal.knownValue;
162                }
163        }
164
165        auto it = enumValues.find( enumerator->name );
166
167        if ( it != enumValues.end() ) {
168
169                // Handle typed enum by casting the value in (C++) compiler
170                // if ( base ) { // A typed enum
171                //      if ( const BasicType * bt = dynamic_cast<const BasicType *>(base) ) {
172                //              switch( bt->kind ) {
173                //                      case BasicType::Kind::Bool:     value = (bool) it->second; break;
174                //                      case BasicType::Kind::Char: value = (char) it->second; break;
175                //                      case BasicType::Kind::SignedChar: value = (signed char) it->second; break;
176                //                      case BasicType::Kind::UnsignedChar: value = (unsigned char) it->second; break;
177                //                      case BasicType::Kind::ShortSignedInt: value = (short signed int) it->second; break;
178                //                      case BasicType::Kind::SignedInt: value = (signed int) it->second; break;
179                //                      case BasicType::Kind::UnsignedInt: value = (unsigned int) it->second; break;
180                //                      case BasicType::Kind::LongSignedInt: value = (long signed int) it->second; break;
181                //                      case BasicType::Kind::LongUnsignedInt: value = (long unsigned int) it->second; break;
182                //                      case BasicType::Kind::LongLongSignedInt: value = (long long signed int) it->second; break;
183                //                      case BasicType::Kind::LongLongUnsignedInt: value = (long long unsigned int) it->second; break;
184                //                      // TODO: value should be able to handle long long unsigned int
185
186                //                      default:
187                //                      value = it->second;
188                //              }
189                //      }
190                // } else {
191                        value = it->second;
192                //}
193
194                return true;
195        }
196        return false;
197}
198
199}
200
201// Local Variables: //
202// tab-width: 4 //
203// mode: c++ //
204// compile-command: "make install" //
205// End: //
Note: See TracBrowser for help on using the repository browser.