source: src/Validate/ForallPointerDecay.cpp@ a0b59ed

Last change on this file since a0b59ed was b7c53a9d, checked in by Andrew Beach <ajbeach@…>, 2 years ago

Added a new invariant check and the fixes required to make it pass. Not the new check is by no means exaustive (it doesn't even check every readonly pointer) but it should catch the most common/problematic cases.

  • Property mode set to 100644
File size: 7.3 KB
Line 
1//
2// Cforall Version 1.0.0 Copyright (C) 2018 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// ForallPointerDecay.cpp --
8//
9// Author : Andrew Beach
10// Created On : Tue Dec 7 16:15:00 2021
11// Last Modified By : Andrew Beach
12// Last Modified On : Sat Apr 23 13:10:00 2022
13// Update Count : 1
14//
15
16#include "ForallPointerDecay.hpp"
17
18#include "AST/Copy.hpp"
19#include "AST/Decl.hpp"
20#include "AST/DeclReplacer.hpp"
21#include "AST/Pass.hpp"
22#include "CodeGen/OperatorTable.h"
23#include "Common/CodeLocation.h"
24#include "Common/ToString.hpp"
25#include "Common/utility.h"
26#include "SymTab/FixFunction.h"
27
28namespace Validate {
29
30namespace {
31
32// Create a function type only using information on the FunctionDecl.
33ast::FunctionType * makeFuncType( const ast::FunctionDecl * decl ) {
34 auto type = new ast::FunctionType( decl->type->isVarArgs );
35 for ( auto & param : decl->params ) {
36 type->params.emplace_back( param->get_type() );
37 }
38 for ( auto & ret : decl->returns ) {
39 type->returns.emplace_back( ret->get_type() );
40 }
41 for ( auto & type_param : decl->type_params ) {
42 type->forall.emplace_back(
43 new ast::TypeInstType( type_param ) );
44 }
45 for ( auto & assertion : decl->assertions ) {
46 type->assertions.emplace_back( new ast::VariableExpr(
47 assertion->location, assertion ) );
48 }
49 return type;
50}
51
52ast::FunctionDecl * updateAssertions( ast::FunctionDecl * decl ) {
53 auto type = ast::mutate( decl->type.get() );
54 type->assertions.clear();
55 type->assertions.reserve( decl->assertions.size() );
56 for ( auto & assertion : decl->assertions ) {
57 type->assertions.emplace_back(
58 new ast::VariableExpr( decl->location, assertion ) );
59 }
60 decl->type = type;
61 return decl;
62}
63
64// Component Passes:
65/// Expand assertions from a trait instance,
66/// performing appropriate type variable substitutions.
67struct TraitExpander final {
68 using AssertionList = std::vector<ast::ptr<ast::DeclWithType>>;
69
70 static AssertionList expandTrait( const ast::TraitInstType * inst ) {
71 assertf( inst->base, "Trait instance not linked to base trait: %s",
72 toCString( inst ) );
73 AssertionList assertions;
74 // Substitute trait decl parameters for instance parameters.
75 ast::TypeSubstitution sub( inst->base->params, inst->params );
76 for ( const ast::ptr<ast::Decl> & decl : inst->base->members ) {
77 ast::ptr<ast::DeclWithType> copy =
78 ast::deepCopy( decl.strict_as<ast::DeclWithType>() );
79
80 int count = sub.apply( copy );
81 (void)count;
82
83 // Update the type (type substution does not seem to cover it).
84 if ( auto func = copy.as<ast::FunctionDecl>() ) {
85 auto mut = ast::mutate( func );
86 mut->type = makeFuncType( func );
87 copy = mut;
88 }
89 assertions.push_back( copy );
90 }
91 return assertions;
92 }
93
94 static AssertionList expandAssertions( const AssertionList & old ) {
95 AssertionList assertions;
96 for ( const ast::ptr<ast::DeclWithType> & decl : old ) {
97 if ( auto traitInst = dynamic_cast<const ast::TraitInstType *>(
98 decl->get_type() ) ) {
99 auto moreAsserts = expandTrait( traitInst );
100 splice( assertions, moreAsserts );
101 } else {
102 assertions.push_back( decl );
103 }
104 }
105 return assertions;
106 }
107
108 using TypeDeclVec = std::vector<ast::ptr<ast::TypeDecl>>;
109
110 static TypeDeclVec expandTypeDecls( const TypeDeclVec & old ) {
111 TypeDeclVec typeDecls;
112 typeDecls.reserve( old.size() );
113 for ( const ast::TypeDecl * typeDecl : old ) {
114 typeDecls.push_back( ast::mutate_field( typeDecl,
115 &ast::TypeDecl::assertions,
116 expandAssertions( typeDecl->assertions ) ) );
117 }
118 return typeDecls;
119 }
120
121 const ast::FunctionDecl * postvisit( const ast::FunctionDecl * decl ) {
122 if ( decl->assertions.empty() ) {
123 return decl;
124 }
125 auto mut = ast::mutate( decl );
126 mut->assertions = expandAssertions( decl->assertions );
127 // Update the assertion list on the type as well.
128 return updateAssertions( mut );
129 }
130
131 const ast::StructDecl * previsit( const ast::StructDecl * decl ) {
132 if ( decl->params.empty() ) {
133 return decl;
134 }
135 return ast::mutate_field( decl, &ast::StructDecl::params,
136 expandTypeDecls( decl->params ) );
137 }
138
139 const ast::UnionDecl * previsit( const ast::UnionDecl * decl ) {
140 if ( decl->params.empty() ) {
141 return decl;
142 }
143 return ast::mutate_field( decl, &ast::UnionDecl::params,
144 expandTypeDecls( decl->params ) );
145 }
146};
147
148std::vector<ast::ptr<ast::DeclWithType>> fixAssertionList(
149 const ast::ParseNode * node,
150 const std::vector<ast::ptr<ast::DeclWithType>> & assertions ) {
151 std::vector<ast::ptr<ast::DeclWithType>> ret;
152 ret.reserve( assertions.size() );
153 for ( const auto & assn : assertions ) {
154 bool isVoid = false;
155 ret.push_back( SymTab::fixFunction( assn, isVoid ) );
156 if ( isVoid ) {
157 SemanticError( node->location, node,
158 "invalid type void in assertion of function " );
159 }
160 }
161 return ret;
162}
163
164std::vector<ast::ptr<ast::TypeDecl>> fixTypeDeclList(
165 const ast::ParseNode * node,
166 const std::vector<ast::ptr<ast::TypeDecl>> & type_params ) {
167 std::vector<ast::ptr<ast::TypeDecl>> ret;
168 ret.reserve( type_params.size() );
169 for ( const ast::TypeDecl * type_param : type_params ) {
170 auto mutParam = ast::mutate( type_param );
171 mutParam->assertions = fixAssertionList( node, mutParam->assertions );
172 ret.push_back( mutParam );
173 }
174 return ret;
175}
176
177struct AssertionFunctionFixer final {
178 const ast::FunctionDecl * previsit( const ast::FunctionDecl * decl ) {
179 if ( decl->assertions.empty() ) {
180 return decl;
181 }
182 return ast::mutate_field( decl, &ast::FunctionDecl::assertions,
183 fixAssertionList( decl, decl->assertions ) );
184 }
185
186 const ast::FunctionDecl * postvisit( const ast::FunctionDecl * decl ) {
187 if ( decl->assertions.empty() ) {
188 return decl;
189 }
190 return updateAssertions( mutate( decl ) );
191 }
192
193 const ast::StructDecl * previsit( const ast::StructDecl * decl ) {
194 if ( decl->params.empty() ) {
195 return decl;
196 }
197 return ast::mutate_field( decl, &ast::StructDecl::params,
198 fixTypeDeclList( decl, decl->params ) );
199 }
200
201 const ast::UnionDecl * previsit( const ast::UnionDecl * decl ) {
202 if ( decl->params.empty() ) {
203 return decl;
204 }
205 return ast::mutate_field( decl, &ast::UnionDecl::params,
206 fixTypeDeclList( decl, decl->params ) );
207 }
208};
209
210struct OperatorChecker final {
211 void previsit( const ast::ObjectDecl * obj ) {
212 if ( !CodeGen::isOperator( obj->name ) ) return;
213 auto type = obj->type->stripDeclarator();
214 if ( dynamic_cast< const ast::FunctionType * >( type ) ) return;
215 SemanticError( obj->location,
216 toCString( "operator ", obj->name.c_str(), " is not "
217 "a function or function pointer." ) );
218 }
219};
220
221struct UniqueFixCore final {
222 const ast::DeclWithType * postvisit( const ast::DeclWithType * decl ) {
223 if ( decl->uniqueId ) {
224 return decl;
225 } else {
226 auto mut = ast::mutate( decl );
227 mut->fixUniqueId();
228 return mut;
229 }
230 }
231};
232
233} // namespace
234
235void decayForallPointers( ast::TranslationUnit & transUnit ) {
236 ast::Pass<TraitExpander>::run( transUnit );
237 ast::Pass<AssertionFunctionFixer>::run( transUnit );
238 ast::Pass<OperatorChecker>::run( transUnit );
239 ast::Pass<UniqueFixCore>::run( transUnit );
240}
241
242std::vector<ast::ptr<ast::DeclWithType>> expandAssertions(
243 std::vector<ast::ptr<ast::DeclWithType>> const & old ) {
244 return TraitExpander::expandAssertions( old );
245}
246
247} // namespace Validate
248
249// Local Variables: //
250// tab-width: 4 //
251// mode: c++ //
252// compile-command: "make install" //
253// End: //
Note: See TracBrowser for help on using the repository browser.