source: src/AST/Decl.cpp@ 994030ce

Last change on this file since 994030ce was 8f557161, checked in by Michael Brooks <mlbrooks@…>, 2 years 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.