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
RevLine 
[2bb4a01]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
[7edd5c1]11// Last Modified By : Andrew Beach
12// Last Modified On : Thu May 5 12:10:00 2022
13// Update Count : 24
[2bb4a01]14//
15
16#include "Decl.hpp"
17
[360b2e13]18#include <cassert> // for assert, strict_dynamic_cast
[d76c588]19#include <iostream>
[360b2e13]20#include <unordered_map>
21
[8f06277]22#include "Common/Eval.h" // for eval
[87701b6]23
[360b2e13]24#include "Fwd.hpp" // for UniqueId
[a300e4a]25#include "Init.hpp"
[360b2e13]26#include "Node.hpp" // for readonly
[87701b6]27#include "Type.hpp" // for readonly
[a4a6802]28#include "Expr.hpp"
[2bb4a01]29
30namespace ast {
[a300e4a]31
[2bb4a01]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;
[7d7ef6f]41 // The extra readonly pointer is causing some reference counting issues.
42 // idMap[ uniqueId ] = this;
[2bb4a01]43}
44
45readonly<Decl> Decl::fromId( UniqueId id ) {
[7d7ef6f]46 // Right now this map is always empty, so don't use it.
[9490621]47 assert( false );
[2bb4a01]48 IdMapType::const_iterator i = idMap.find( id );
49 if ( i != idMap.end() ) return i->second;
50 return {};
51}
[a300e4a]52
[8a5530c]53// --- FunctionDecl
54
[7edd5c1]55FunctionDecl::FunctionDecl( const CodeLocation & loc, const std::string & name,
[3e5dd913]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,
[3e94a23]59 std::vector<ptr<Attribute>>&& attrs, Function::Specs fs, ArgumentFlag isVarArgs )
[b859f59]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 ) {
[3e94a23]63 FunctionType * ftype = new FunctionType( isVarArgs );
[3e5dd913]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) {
[b230091]71 ftype->forall.emplace_back(new TypeInstType(tp));
[a4a6802]72 for (auto & ap: tp->assertions) {
73 ftype->assertions.emplace_back(new VariableExpr(loc, ap));
74 }
[3e5dd913]75 }
76 this->type = ftype;
77}
[490fb92e]78
[7edd5c1]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,
[3e94a23]83 std::vector<ptr<Attribute>>&& attrs, Function::Specs fs, ArgumentFlag isVarArgs )
[7edd5c1]84: DeclWithType( location, name, storage, linkage, std::move(attrs), fs ),
85 type_params( std::move( forall) ), assertions( std::move( assertions ) ),
[b859f59]86 params( std::move(params) ), returns( std::move(returns) ),
[7edd5c1]87 type( nullptr ), stmts( stmts ) {
[3e94a23]88 FunctionType * type = new FunctionType( isVarArgs );
[7edd5c1]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
[490fb92e]105
[87701b6]106const Type * FunctionDecl::get_type() const { return type.get(); }
[e0e9a0b]107void FunctionDecl::set_type( const Type * t ) {
108 type = strict_dynamic_cast< const FunctionType * >( t );
109}
[8a5530c]110
[360b2e13]111// --- TypeDecl
112
[312029a]113const char * TypeDecl::typeString() const {
[6e50a6b]114 static const char * kindNames[] = { "sized data type", "sized data type", "sized object type", "sized function type", "sized tuple type", "sized length value" };
[b66d14a]115 static_assert( sizeof(kindNames) / sizeof(kindNames[0]) == TypeDecl::NUMBER_OF_KINDS, "typeString: kindNames is out of sync." );
[07de76b]116 assertf( kind < TypeDecl::NUMBER_OF_KINDS, "TypeDecl kind is out of bounds." );
[312029a]117 return sized ? kindNames[ kind ] : &kindNames[ kind ][ sizeof("sized") ]; // sizeof includes '\0'
[360b2e13]118}
119
[312029a]120const char * TypeDecl::genTypeString() const {
[b66d14a]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." );
[07de76b]123 assertf( kind < TypeDecl::NUMBER_OF_KINDS, "TypeDecl kind is out of bounds." );
[360b2e13]124 return kindNames[ kind ];
125}
126
[93c10de]127std::ostream & operator<< ( std::ostream & out, const TypeData & data ) {
[d76c588]128 return out << data.kind << ", " << data.isComplete;
129}
130
[312029a]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
[a300e4a]140// --- EnumDecl
141
[9d6e7fa9]142bool EnumDecl::valueOf( const Decl * enumerator, long long& value ) const {
[a300e4a]143 if ( enumValues.empty() ) {
[8f557161]144 Evaluation crntVal = {0, true, true}; // until expression is given, we know to start counting from 0
[9d6e7fa9]145 for ( const Decl * member : members ) {
[a300e4a]146 const ObjectDecl* field = strict_dynamic_cast< const ObjectDecl* >( member );
147 if ( field->init ) {
[87701b6]148 const SingleInit * init = strict_dynamic_cast< const SingleInit* >( field->init.get() );
[8f557161]149 crntVal = eval( init->value );
150 if ( ! crntVal.isEvaluableInGCC ) {
[733074e]151 SemanticError( init->location, ::toString( "Non-constexpr in initialization of "
[a300e4a]152 "enumerator: ", field ) );
153 }
154 }
155 if ( enumValues.count( field->name ) != 0 ) {
[733074e]156 SemanticError( location, ::toString( "Enum ", name, " has multiple members with the " "name ", field->name ) );
[a300e4a]157 }
[8f557161]158 if (crntVal.hasKnownValue) {
159 enumValues[ field->name ] = crntVal.knownValue;
160 }
161 ++crntVal.knownValue;
[a300e4a]162 }
163 }
164
165 auto it = enumValues.find( enumerator->name );
[b859f59]166
[a300e4a]167 if ( it != enumValues.end() ) {
[b859f59]168
[f135b50]169 // Handle typed enum by casting the value in (C++) compiler
[3e54399]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;
[b859f59]183 // case BasicType::Kind::LongLongUnsignedInt: value = (long long unsigned int) it->second; break;
[3e54399]184 // // TODO: value should be able to handle long long unsigned int
185
186 // default:
187 // value = it->second;
188 // }
189 // }
190 // } else {
[f135b50]191 value = it->second;
[3e54399]192 //}
[f135b50]193
[a300e4a]194 return true;
195 }
196 return false;
197}
198
[2bb4a01]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.