source: src/ResolvExpr/ResolveTypeof.cpp @ 50e04cc

Last change on this file since 50e04cc was 81e768d, checked in by Michael Brooks <mlbrooks@…>, 3 weeks ago

Fix #276; add support for c-array parameters using dependent lengths.

Without this fix, declarations like

void f( int m, int n, float[m][n] );

would either

  • generate bad C code, with unmangled variable names appearing in the function definition, or
  • refuse to resolve a valid-c call of such a function.

tests/array-collections/c-dependent: add direct tests of such cases
tests/tuplearray: activate and expand cases which were blocked on #276
tests/array: activate case fm5y, which was blocked on #276; [noise] adjust source line numbers in .expect
tests/typedefRedef: expand coverage of "error, an array detail is different" cases; [noise] adjust source line numbers in .expect
tests/functions: [noise] adjust .expect to have resolved array sizes (extra casts) in the diffed code dump

The fix is:

  • (ResolvExpr/ResolveTypeof?, ResolvExpr/Resolver?) Resolve the dimension expressions, where they were missed.
  • (ResolvExpr/Resolver?) Prevent dimension expressions that are bound to other parameters from escaping in the function's type, to where they are out of scope. In the f example above, redact the type shown to callers from void (*)(int, int, float[m][n]) to void (*)(int, int, float[][*]).
  • (ResolvExpr/Unify?) Relax the matching rules for such a type, when used at a call site, letting the patameters wildcard type match with the concrete type in scope at the caller's side.
  • (Validate/ReplaceTypedef?) Apply the former, stricter matching rules to the one place where they are still needed: detecting inconsistent typedefs.
  • Property mode set to 100644
File size: 6.9 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// ResolveTypeof.cpp --
8//
9// Author           : Richard C. Bilson
10// Created On       : Sun May 17 12:12:20 2015
11// Last Modified By : Andrew Beach
12// Last Modified On : Wed Mar 16 16:09:00 2022
13// Update Count     : 4
14//
15
16#include "ResolveTypeof.hpp"
17
18#include <cassert>                  // for assert
19
20#include "AST/CVQualifiers.hpp"
21#include "AST/Node.hpp"
22#include "AST/Pass.hpp"
23#include "AST/TranslationUnit.hpp"
24#include "AST/Type.hpp"
25#include "AST/TypeEnvironment.hpp"
26#include "Common/Utility.hpp"       // for copy
27#include "InitTweak/InitTweak.hpp"  // for isConstExpr
28#include "RenameVars.hpp"
29#include "Resolver.hpp"             // for resolveInVoidContext
30#include "SymTab/Mangler.hpp"
31
32namespace ResolvExpr {
33
34namespace {
35
36struct ResolveTypeof : public ast::WithShortCircuiting {
37        const ResolveContext & context;
38
39        ResolveTypeof( const ResolveContext & context ) : context( context ) {}
40
41        void previsit( const ast::TypeofType * ) { visit_children = false; }
42
43        const ast::Type * postvisit( const ast::TypeofType * typeofType ) {
44                // pass on null expression
45                if ( ! typeofType->expr ) return typeofType;
46
47                ast::ptr< ast::Type > newType;
48                if ( auto tyExpr = typeofType->expr.as< ast::TypeExpr >() ) {
49                        // typeof wrapping type
50                        newType = tyExpr->type;
51                } else {
52                        // typeof wrapping expression
53                        ast::TypeEnvironment dummy;
54                        ast::ptr< ast::Expr > newExpr =
55                                resolveInVoidContext( typeofType->expr, context, dummy );
56                        assert( newExpr->result && ! newExpr->result->isVoid() );
57                        newType = newExpr->result;
58                }
59
60                // clear qualifiers for base, combine with typeoftype quals regardless
61                if ( typeofType->kind == ast::TypeofType::Basetypeof ) {
62                        // replace basetypeof(<enum>) by int
63                        auto enumInst = newType.as< ast::EnumInstType >();
64                        if ( enumInst && (!enumInst->base || !enumInst->base->isCfa) ) {
65                                newType = new ast::BasicType(
66                                        ast::BasicKind::SignedInt, newType->qualifiers, copy(newType->attributes) );
67                        }
68                        reset_qualifiers(
69                                newType,
70                                ( newType->qualifiers & ~ast::CV::EquivQualifiers ) | typeofType->qualifiers );
71                } else {
72                        add_qualifiers( newType, typeofType->qualifiers );
73                }
74
75                return newType.release();
76        }
77};
78
79} // anonymous namespace
80
81const ast::Type * resolveTypeof( const ast::Type * type , const ResolveContext & context ) {
82        ast::Pass< ResolveTypeof > mutator( context );
83        return type->accept( mutator );
84}
85
86struct FixArrayDimension {
87        const ResolveContext & context;
88        FixArrayDimension(const ResolveContext & context) : context( context ) {}
89
90        template< typename PtrType >
91        const PtrType * previsitImpl( const PtrType * type ) {
92                // Note: resolving dimension expressions seems to require duplicate logic,
93                // here and Resolver.cpp: handlePtrType
94
95                if (!type->dimension) return type;
96                auto mutType = mutate(type);
97                auto globalSizeType = context.global.sizeType;
98                ast::ptr<ast::Type> sizetype = globalSizeType ? globalSizeType : new ast::BasicType( ast::BasicKind::LongUnsignedInt );
99                mutType->dimension = findSingleExpression(type->dimension, sizetype, context );
100
101                if (InitTweak::isConstExpr(mutType->dimension)) {
102                        mutType->isVarLen = ast::LengthFlag::FixedLen;
103                }
104                else {
105                        mutType->isVarLen = ast::LengthFlag::VariableLen;
106                }
107                return mutType;
108        }
109
110        const ast::ArrayType * previsit (const ast::ArrayType * arrayType) {
111                return previsitImpl( arrayType );
112        }
113
114        const ast::PointerType * previsit (const ast::PointerType * pointerType) {
115                return previsitImpl( pointerType );
116        }
117};
118
119const ast::Type * fixArrayType( const ast::Type * type, const ResolveContext & context ) {
120        ast::Pass<FixArrayDimension> visitor(context);
121        return type->accept(visitor);
122}
123
124const ast::ObjectDecl * fixObjectType( const ast::ObjectDecl * decl , const ResolveContext & context ) {
125        if ( decl->isTypeFixed ) {
126                return decl;
127        }
128
129        auto mutDecl = mutate(decl);
130        fixObjectInit(decl, context);
131        {
132                auto resolvedType = resolveTypeof(decl->type, context);
133                resolvedType = fixArrayType(resolvedType, context);
134                mutDecl->type = resolvedType;
135        }
136
137        // Do not mangle unnamed variables.
138        if ( !mutDecl->name.empty() ) {
139                mutDecl->mangleName = Mangle::mangle(mutDecl);
140        }
141
142        mutDecl->type = renameTyVars(mutDecl->type, RenameMode::GEN_EXPR_ID);
143        mutDecl->isTypeFixed = true;
144
145        auto enumInst = decl->type.as<ast::EnumInstType>();
146        if ( enumInst && enumInst->base->isCfa ) {
147                if ( auto init = decl->init.as<ast::SingleInit>() ) {
148                        if ( auto initExpr = init->value.as<ast::ConstantExpr>() ) {
149                                if ( initExpr->result.as<ast::ZeroType>() ) {
150                                        auto newInit = new ast::SingleInit( init->location, 
151                                                ast::UntypedExpr::createCall( init->location, "lowerBound", {} )
152                                        );
153                                        mutDecl->init = newInit;
154                                }
155                        }
156                }
157        }
158
159        return mutDecl;
160}
161
162const ast::ObjectDecl *fixObjectInit(
163                const ast::ObjectDecl *decl, const ResolveContext &context) {
164        if ( decl->isTypeFixed ) {
165                return decl;
166        }
167
168        if ( auto listInit = decl->init.as<ast::ListInit>() ) {
169                for ( size_t k = 0; k < listInit->designations.size(); k++ ) {
170                        const ast::Designation *des = listInit->designations[k].get();
171                        // Desination here
172                        ast::Designation * newDesignation = new ast::Designation(des->location);
173                        std::deque<ast::ptr<ast::Expr>> newDesignators;
174
175                        for ( ast::ptr<ast::Expr> designator : des->designators ) {
176                                // Stupid flag variable for development, to be removed
177                                if ( const ast::NameExpr * designatorName = designator.as<ast::NameExpr>() ) {
178                                        auto candidates = context.symtab.lookupId(designatorName->name);
179                                        // Does not work for the overloading case currently
180                                        // assert( candidates.size() == 1 );
181                                        if ( candidates.size() != 1 ) return decl;
182                                        auto candidate = candidates.at(0);
183                                        if ( const ast::EnumInstType * enumInst = dynamic_cast<const ast::EnumInstType *>(candidate.id->get_type())) {
184                                                // determine that is an enumInst, swap it with its const value
185                                                assert( candidates.size() == 1 );
186                                                const ast::EnumDecl * baseEnum = enumInst->base;
187                                                // Need to iterate over all enum value to find the initializer to swap
188                                                for ( size_t m = 0; m < baseEnum->members.size(); ++m ) {
189                                                        const ast::ObjectDecl * mem = baseEnum->members.at(m).as<const ast::ObjectDecl>();
190                                                        if ( baseEnum->members.at(m)->name == designatorName->name ) {
191                                                                assert( mem );
192                                                                newDesignators.push_back( ast::ConstantExpr::from_int(designator->location, m) );
193                                                                break;
194                                                        }
195                                                }
196                                        } else {
197                                                newDesignators.push_back( des->designators.at(0) );
198                                        }
199                                } else {
200                                        newDesignators.push_back( des->designators.at(0) );
201                                }
202                        }
203                        newDesignation->designators = newDesignators;
204                        listInit = ast::mutate_field_index(listInit, &ast::ListInit::designations, k, newDesignation);
205                }
206        }
207        return decl;
208}
209
210} // namespace ResolvExpr
211
212// Local Variables: //
213// tab-width: 4 //
214// mode: c++ //
215// compile-command: "make install" //
216// End: //
Note: See TracBrowser for help on using the repository browser.