source: src/AST/Decl.cpp @ d10e391

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