source: src/Validate/ImplementEnumFunc.cpp@ 793eb2f

Last change on this file since 793eb2f was 5ccc733, checked in by JiadaL <j82liang@…>, 15 months ago

Fix the bug that C style enum cannot to use as an lvalue

  • Property mode set to 100644
File size: 16.4 KB
RevLine 
[af746cc]1#include "AST/Create.hpp"
2#include "AST/Pass.hpp"
3#include "AST/TranslationUnit.hpp"
[c92bdcc]4#include "CodeGen/OperatorTable.hpp" // for isCtorDtor, isCtorDtorAssign
5#include "InitTweak/InitTweak.hpp" // for isAssignment, isCopyConstructor
[af746cc]6namespace Validate {
7
8namespace {
9class EnumAttrFuncGenerator {
[fc1a3e2]10 const ast::EnumDecl* decl;
11 unsigned int functionNesting;
[85855b0]12 const ast::StructDecl* quasi_void_decl;
[fc1a3e2]13 ast::Linkage::Spec proto_linkage;
14
15public:
16 std::list<ast::ptr<ast::Decl>> forwards;
17 std::list<ast::ptr<ast::Decl>> definitions;
18
19 void generateAndAppendFunctions(std::list<ast::ptr<ast::Decl>>&);
20
21 EnumAttrFuncGenerator(
22 const ast::EnumDecl* decl,
[822332e]23 const ast::EnumInstType*,
[fc1a3e2]24 unsigned int functionNesting )
25 : decl(decl),
26 functionNesting{functionNesting},
[85855b0]27 quasi_void_decl(new ast::StructDecl(decl->location,
28 "quasi_void", ast::AggregateDecl::Struct,
29 {}, ast::Linkage::AutoGen)),
[fc1a3e2]30 proto_linkage{ast::Linkage::Cforall} {}
31
32private:
33 const CodeLocation& getLocation() const { return decl->location; }
34
35 ast::FunctionDecl* genProto(
36 std::string&& name, std::vector<ast::ptr<ast::DeclWithType>>&& params,
37 std::vector<ast::ptr<ast::DeclWithType>>&& returns) const;
38
39 void produceDecl(const ast::FunctionDecl* decl);
40 void produceForwardDecl(const ast::FunctionDecl* decl);
41
42 const ast::Decl* getDecl() const { return decl; }
43
[c333ed2]44 // Implement Bounded trait
45 void genBoundedFunctions();
46 ast::FunctionDecl* genBoundedProto(const char *) const;
47 void genBoundedBody(ast::FunctionDecl* func) const;
[eb7586e]48
[c333ed2]49 // Implement Serial trait
50 void genSerialTraitFuncs();
51 ast::FunctionDecl* genFromIntProto() const;
52 ast::FunctionDecl* genFromInstanceProto() const;
53 ast::FunctionDecl* genInstToInstFuncProto(const char* func) const;
[822332e]54 void genFromIntBody(ast::FunctionDecl *) const;
[c333ed2]55 void genFromInstanceBody(ast::FunctionDecl *) const;
56 void genSuccPredBody(ast::FunctionDecl *, const char *) const;
[eb7586e]57
[85855b0]58 void genTypeNameFunc();
59
[c333ed2]60 // Implement TypedEnum trait
61 void genTypedEnumFuncs();
62 void genTypedEnumFunction(const ast::EnumAttribute attr);
[fc1a3e2]63 ast::FunctionDecl* genPosnProto() const;
64 ast::FunctionDecl* genLabelProto() const;
65 ast::FunctionDecl* genValueProto() const;
[85855b0]66 ast::FunctionDecl* genQuasiValueProto() const;
67 ast::FunctionDecl* genTypeNameProto() const;
68
[c333ed2]69 void genValueOrLabelBody(
70 ast::FunctionDecl* func, ast::ObjectDecl* arrDecl) const;
71 void genPosnBody(ast::FunctionDecl* func) const;
[85855b0]72 void genQuasiValueBody(ast::FunctionDecl* func) const;
73 void genTypeNameBody(ast::FunctionDecl* func) const;
[fc1a3e2]74
75 // ----------------------------------------------------
76
77 const ast::Init* getAutoInit(const ast::Init* prev) const;
78
79 std::vector<ast::ptr<ast::Init>> genLabelInit() const;
80
81 std::vector<ast::ptr<ast::Init>> genValueInit() const;
82 ast::ObjectDecl* genAttrArrayProto(
83 const ast::EnumAttribute attr, const CodeLocation& location,
84 std::vector<ast::ptr<ast::Init>>& inits) const;
[af746cc]85};
86
87std::vector<ast::ptr<ast::Init>> EnumAttrFuncGenerator::genLabelInit() const {
[fc1a3e2]88 std::vector<ast::ptr<ast::Init>> inits;
89 for (size_t i = 0; i < decl->members.size(); i++) {
90 ast::ptr<ast::Decl> mem = decl->members.at(i);
91 auto memAsObjectDecl = mem.as<ast::ObjectDecl>();
92 assert(memAsObjectDecl);
93 inits.emplace_back(new ast::SingleInit(
94 mem->location,
95 ast::ConstantExpr::from_string(mem->location, mem->name)));
96 }
97 return inits;
[af746cc]98}
99
100std::vector<ast::ptr<ast::Init>> EnumAttrFuncGenerator::genValueInit() const {
[fc1a3e2]101 std::vector<ast::ptr<ast::Init>> inits;
102 for (size_t i = 0; i < decl->members.size(); i++) {
103 ast::ptr<ast::Decl> mem = decl->members.at(i);
104 auto memAsObjectDecl = mem.as<ast::ObjectDecl>();
105 assert(memAsObjectDecl);
106 if (memAsObjectDecl->init) {
107 inits.emplace_back(memAsObjectDecl->init);
108 } else {
109 const CodeLocation& location = mem->location;
110 if (i == 0) {
111 inits.emplace_back(new ast::SingleInit(
112 location, ast::ConstantExpr::from_int(mem->location, 0)));
113 } else {
114 inits.emplace_back(getAutoInit(inits.at(i - 1)));
115 }
116 }
117 }
118 return inits;
[af746cc]119}
[85855b0]120
[af746cc]121const ast::Init* EnumAttrFuncGenerator::getAutoInit(
[fc1a3e2]122 const ast::Init* prev) const {
123 if (prev == nullptr) {
124 return new ast::SingleInit(
125 getLocation(), ast::ConstantExpr::from_int(getLocation(), 0));
126 }
127 auto prevInit = dynamic_cast<const ast::SingleInit*>(prev);
128 assert(prevInit);
129 auto prevInitExpr = prevInit->value;
130 if (auto constInit = prevInitExpr.as<ast::ConstantExpr>()) {
131 // Assume no string literal for now
132 return new ast::SingleInit(
133 getLocation(), ast::ConstantExpr::from_int(
134 getLocation(), constInit->intValue() + 1));
135 } else {
136 auto untypedThisInit = new ast::UntypedExpr(
137 getLocation(), new ast::NameExpr(getLocation(), "?++"),
138 {prevInitExpr});
139 return new ast::SingleInit(getLocation(), untypedThisInit);
140 }
[af746cc]141}
142
143ast::FunctionDecl* EnumAttrFuncGenerator::genProto(
[fc1a3e2]144 std::string&& name, std::vector<ast::ptr<ast::DeclWithType>>&& params,
145 std::vector<ast::ptr<ast::DeclWithType>>&& returns) const {
146 ast::FunctionDecl* decl = new ast::FunctionDecl(
147 // Auto-generated routines use the type declaration's location.
148 getLocation(), std::move(name), {}, {}, std::move(params),
149 std::move(returns),
150 // Only a prototype, no body.
151 nullptr,
152 // Use static storage if we are at the top level.
153 (0 < functionNesting) ? ast::Storage::Classes() : ast::Storage::Static,
154 proto_linkage, std::vector<ast::ptr<ast::Attribute>>(),
155 // Auto-generated routines are inline to avoid conflicts.
156 ast::Function::Specs(ast::Function::Inline));
157 decl->fixUniqueId();
158 return decl;
[af746cc]159}
160
161void EnumAttrFuncGenerator::produceDecl(const ast::FunctionDecl* decl) {
[fc1a3e2]162 assert(nullptr != decl->stmts);
[af746cc]163
[fc1a3e2]164 definitions.push_back(decl);
[af746cc]165}
166
167void EnumAttrFuncGenerator::produceForwardDecl(const ast::FunctionDecl* decl) {
[fc1a3e2]168 if (0 != functionNesting) return;
169 ast::FunctionDecl* fwd =
170 (decl->stmts) ? ast::asForward(decl) : ast::deepCopy(decl);
171 fwd->fixUniqueId();
172 forwards.push_back(fwd);
[af746cc]173}
174
175ast::FunctionDecl* EnumAttrFuncGenerator::genPosnProto() const {
176 return genProto(
[5eb3f65]177 "posn",
[af746cc]178 {new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))},
179 {new ast::ObjectDecl(getLocation(), "_ret",
[cf191ac]180 new ast::BasicType(ast::BasicKind::UnsignedInt))});
[af746cc]181}
182
183ast::FunctionDecl* EnumAttrFuncGenerator::genLabelProto() const {
[fc1a3e2]184 return genProto(
[5eb3f65]185 "label",
[fc1a3e2]186 {new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))},
187 {new ast::ObjectDecl(
188 getLocation(), "_ret",
189 new ast::PointerType(new ast::BasicType{ast::BasicKind::Char}))});
[af746cc]190}
191
192ast::FunctionDecl* EnumAttrFuncGenerator::genValueProto() const {
[85855b0]193 if (decl->base)
194 return genProto(
[5eb3f65]195 "value",
[85855b0]196 {new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))},
197 {new ast::ObjectDecl(getLocation(), "_ret",
198 ast::deepCopy(decl->base))});
199 else
200 return genQuasiValueProto();
201}
202
203ast::FunctionDecl* EnumAttrFuncGenerator::genQuasiValueProto() const {
[fc1a3e2]204 return genProto(
[5eb3f65]205 "value",
[fc1a3e2]206 {new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))},
207 {new ast::ObjectDecl(getLocation(), "_ret",
[85855b0]208 new ast::StructInstType(quasi_void_decl))});
[af746cc]209}
210
[eb7586e]211ast::FunctionDecl* EnumAttrFuncGenerator::genFromIntProto() const {
212 return genProto(
213 "fromInt",
214 {new ast::ObjectDecl(getLocation(), "_i", new ast::BasicType(ast::BasicKind::UnsignedInt))},
215 {new ast::ObjectDecl(getLocation(), "_ret", new ast::EnumInstType(decl))}
216 );
217}
218
219ast::FunctionDecl* EnumAttrFuncGenerator::genFromInstanceProto() const {
220 return genProto(
221 "fromInstance",
222 {new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))},
223 {new ast::ObjectDecl(getLocation(), "_ret", new ast::BasicType(ast::BasicKind::UnsignedInt))}
224 );
225}
226
[85855b0]227ast::FunctionDecl* EnumAttrFuncGenerator::genTypeNameProto() const {
228 return genProto(
229 "type_name",
230 {new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))},
231 {new ast::ObjectDecl(
232 getLocation(), "_ret",
233 new ast::PointerType(new ast::BasicType{ast::BasicKind::Char}))});
234}
235
[eb7586e]236void EnumAttrFuncGenerator::genFromIntBody(ast::FunctionDecl* func) const {
237 auto params = func->params;
238 assert( params.size() == 1 );
239 auto param = params.front();
240 auto castExpr = new ast::CastExpr(
241 func->location,
242 new ast::VariableExpr(func->location, param),
243 new ast::EnumInstType(decl),
244 ast::GeneratedFlag::ExplicitCast
245 );
246 func->stmts = new ast::CompoundStmt(
247 func->location, {new ast::ReturnStmt(func->location, castExpr)}
248 );
249}
250
251void EnumAttrFuncGenerator::genFromInstanceBody(ast::FunctionDecl* func) const {
252 auto params = func->params;
253 assert( params.size() == 1 );
254 auto param = params.front();
255 ast::UntypedExpr* untyped = ast::UntypedExpr::createCall(
[5eb3f65]256 func->location, "posn", { new ast::VariableExpr(func->location, param) });
[eb7586e]257 func->stmts = new ast::CompoundStmt(
258 func->location, {new ast::ReturnStmt(func->location, untyped)}
259 );
260}
261
[c333ed2]262void EnumAttrFuncGenerator::genSuccPredBody(ast::FunctionDecl * func, const char* opt) const {
263 auto params = func->params;
264 assert( params.size() == 1 );
265 auto param = params.front();
266 auto enumToInt = new ast::CastExpr(
267 func->location,
268 new ast::VariableExpr(func->location, param),
269 new ast::BasicType(ast::BasicKind::UnsignedInt),
270 ast::GeneratedFlag::ExplicitCast
271 );
272 ast::UntypedExpr* addOneExpr = ast::UntypedExpr::createCall( func->location,
273 opt,
274 {enumToInt,
275 ast::ConstantExpr::from_int(func->location, 1)}
276 );
277 auto intToEnum = new ast::CastExpr(
278 func->location,
279 addOneExpr,
280 new ast::EnumInstType( decl ),
281 ast::GeneratedFlag::ExplicitCast
282 );
283 func->stmts = new ast::CompoundStmt(
284 func->location, {
285 new ast::ReturnStmt(
286 func->location,
287 intToEnum
288 )
289 }
290 );
[eb7586e]291}
292
[c333ed2]293void EnumAttrFuncGenerator::genSerialTraitFuncs() {
294 ast::FunctionDecl * protos[4] = {
295 genFromIntProto(),
296 genFromInstanceProto(),
297 genInstToInstFuncProto("succ"),
298 genInstToInstFuncProto("pred")
299 };
300 for (auto& proto: protos) produceForwardDecl(proto);
301 genFromIntBody(protos[0]);
302 genFromInstanceBody(protos[1]);
303 genSuccPredBody(protos[2], "?+?");
304 genSuccPredBody(protos[3], "?-?");
[6d9aa79]305 for (auto& proto: protos) produceDecl(proto);
[c333ed2]306}
307
308ast::FunctionDecl* EnumAttrFuncGenerator::genInstToInstFuncProto(const char * func) const {
[fc1a3e2]309 return genProto(
[c333ed2]310 func,
[fc1a3e2]311 {new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))},
312 {new ast::ObjectDecl(getLocation(), "_ret",
313 new ast::EnumInstType(decl))});
[af746cc]314}
315
[c333ed2]316ast::FunctionDecl* EnumAttrFuncGenerator::genBoundedProto(const char * func) const {
317 return genProto(func, {}, {
[eb7586e]318 new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))
319 });
320}
321
[c333ed2]322void EnumAttrFuncGenerator::genBoundedBody(ast::FunctionDecl* func) const {
[eb7586e]323 const CodeLocation & loc = func->location;
[c333ed2]324 auto mem = func->name=="lowerBound"? decl->members.front() : decl->members.back();
[85855b0]325 // auto expr = new ast::NameExpr( loc, mem->name );
326 auto expr = new ast::QualifiedNameExpr( loc, decl->name, mem->name );
[eb7586e]327 func->stmts = new ast::CompoundStmt( loc, {new ast::ReturnStmt(loc, expr)});
328}
329
330void EnumAttrFuncGenerator::genBoundedFunctions() {
[c333ed2]331 ast::FunctionDecl * boundedProtos[2] = {genBoundedProto("upperBound"), genBoundedProto("lowerBound")};
332 for (auto & protos: boundedProtos) {
333 produceForwardDecl(protos);
334 genBoundedBody(protos);
335 produceDecl(protos);
336 }
[eb7586e]337}
338
[af746cc]339ast::ObjectDecl* EnumAttrFuncGenerator::genAttrArrayProto(
[fc1a3e2]340 const ast::EnumAttribute attr, const CodeLocation& location,
341 std::vector<ast::ptr<ast::Init>>& inits) const {
342 ast::ArrayType* arrT = new ast::ArrayType(
343 attr == ast::EnumAttribute::Value
344 ? decl->base
345 : new ast::PointerType(new ast::BasicType{ast::BasicKind::Char}),
346 ast::ConstantExpr::from_int(decl->location, decl->members.size()),
347 ast::LengthFlag::FixedLen, ast::DimensionFlag::DynamicDim);
348
349 ast::ObjectDecl* objDecl =
350 new ast::ObjectDecl(
351 decl->location, decl->getUnmangeldArrayName( attr ),
352 arrT, new ast::ListInit( location, std::move( inits ) ),
353 ast::Storage::Static, ast::Linkage::AutoGen );
354
355 return objDecl;
[af746cc]356}
357
358void EnumAttrFuncGenerator::genValueOrLabelBody(
[fc1a3e2]359 ast::FunctionDecl* func, ast::ObjectDecl* arrDecl) const {
360 ast::UntypedExpr* untyped = ast::UntypedExpr::createCall(
361 func->location, "?[?]",
362 {new ast::NameExpr(func->location, arrDecl->name),
[eb7586e]363 new ast::CastExpr(
364 func->location,
365 new ast::VariableExpr( func->location, func->params.front() ),
[acb33f15]366 new ast::BasicType( ast::BasicKind::UnsignedInt ),
367 ast::GeneratedFlag::ExplicitCast
368 )});
[fc1a3e2]369 func->stmts = new ast::CompoundStmt(
370 func->location, {new ast::ReturnStmt(func->location, untyped)});
[af746cc]371}
372
[85855b0]373void EnumAttrFuncGenerator::genQuasiValueBody(ast::FunctionDecl* func) const {
374 auto location = func->location;
375 const ast::ObjectDecl * objDecl = new ast::ObjectDecl(
376 location, "_out", new ast::StructInstType( quasi_void_decl ));
377 const ast::DeclStmt * declStmt = new ast::DeclStmt(location, objDecl);
378 const ast::VariableExpr * varExpr = new ast::VariableExpr(location, objDecl);
379 const ast::ReturnStmt * retStmt = new ast::ReturnStmt(location, varExpr);
380
381 func->stmts = new ast::CompoundStmt(
382 location, {declStmt, retStmt}
383 );
384}
385
[af746cc]386void EnumAttrFuncGenerator::genPosnBody(ast::FunctionDecl* func) const {
[fc1a3e2]387 auto castExpr = new ast::CastExpr(
388 func->location,
389 new ast::VariableExpr(func->location, func->params.front()),
[acb33f15]390 new ast::BasicType( ast::BasicKind::UnsignedInt ),
391 ast::GeneratedFlag::ExplicitCast);
[fc1a3e2]392 func->stmts = new ast::CompoundStmt(
393 func->location, {new ast::ReturnStmt(func->location, castExpr)});
[af746cc]394}
395
[85855b0]396void EnumAttrFuncGenerator::genTypeNameBody(ast::FunctionDecl* func) const {
397 const ast::Expr * type_name = ast::ConstantExpr::from_string(func->location, decl->name);
398 func->stmts = new ast::CompoundStmt(
399 func->location, {new ast::ReturnStmt(func->location, type_name)}
400 );
401}
402
[c333ed2]403void EnumAttrFuncGenerator::genTypedEnumFunction(const ast::EnumAttribute attr) {
[85855b0]404 if (attr == ast::EnumAttribute::Value) {
405 if (decl->base) {
406 // TypedEnum's backing arrays
407 std::vector<ast::ptr<ast::Init>> inits = genValueInit();
408 ast::ObjectDecl* arrayProto =
409 genAttrArrayProto(attr, getLocation(), inits);
410 forwards.push_back(arrayProto);
411
412 ast::FunctionDecl* funcProto = genValueProto();
413 produceForwardDecl(funcProto);
414 genValueOrLabelBody(funcProto, arrayProto);
415 produceDecl(funcProto);
416 } else {
417 ast::FunctionDecl* funcProto = genQuasiValueProto();
418 produceForwardDecl(funcProto);
419 genQuasiValueBody(funcProto);
420 produceDecl(funcProto);
421 }
422 } else if (attr == ast::EnumAttribute::Label) {
423 std::vector<ast::ptr<ast::Init>> inits = genLabelInit();
[fc1a3e2]424 ast::ObjectDecl* arrayProto =
425 genAttrArrayProto(attr, getLocation(), inits);
426 forwards.push_back(arrayProto);
[85855b0]427 ast::FunctionDecl* funcProto = genLabelProto();
[fc1a3e2]428 produceForwardDecl(funcProto);
429 genValueOrLabelBody(funcProto, arrayProto);
430 produceDecl(funcProto);
431 } else {
432 ast::FunctionDecl* funcProto = genPosnProto();
433 produceForwardDecl(funcProto);
434 genPosnBody(funcProto);
435 produceDecl(funcProto);
436 }
[af746cc]437}
438
[c333ed2]439void EnumAttrFuncGenerator::genTypedEnumFuncs() {
[85855b0]440 genTypedEnumFunction(ast::EnumAttribute::Value);
[c333ed2]441 genTypedEnumFunction(ast::EnumAttribute::Label);
[822332e]442 genTypedEnumFunction(ast::EnumAttribute::Posn);
[af746cc]443}
444
[85855b0]445void EnumAttrFuncGenerator::genTypeNameFunc() {
446 ast::FunctionDecl* funcProto = genTypeNameProto();
447 produceForwardDecl(funcProto);
448 genTypeNameBody(funcProto);
449 produceDecl(funcProto);
450}
451
[af746cc]452void EnumAttrFuncGenerator::generateAndAppendFunctions(
[fc1a3e2]453 std::list<ast::ptr<ast::Decl>>& decls) {
454 // Generate the functions (they go into forwards and definitions).
[85855b0]455 genTypeNameFunc();
[c333ed2]456 genTypedEnumFuncs();
[eb7586e]457 genSerialTraitFuncs();
458 genBoundedFunctions();
[fc1a3e2]459 // Now export the lists contents.
460 decls.splice(decls.end(), forwards);
461 decls.splice(decls.end(), definitions);
[af746cc]462}
463
464// ---------------------------------------------------------
465
[fc1a3e2]466struct ImplementEnumFunc final :
467 public ast::WithDeclsToAdd<>, public ast::WithShortCircuiting {
468 void previsit(const ast::EnumDecl* enumDecl);
469 void previsit(const ast::FunctionDecl* functionDecl);
470 void postvisit(const ast::FunctionDecl* functionDecl);
[af746cc]471
[fc1a3e2]472private:
473 // Current level of nested functions.
474 unsigned int functionNesting = 0;
[af746cc]475};
476
477void ImplementEnumFunc::previsit(const ast::EnumDecl* enumDecl) {
[5ccc733]478 if (!enumDecl->body || !enumDecl->isCfa) return;
[fc1a3e2]479 ast::EnumInstType enumInst(enumDecl->name);
480 enumInst.base = enumDecl;
481 EnumAttrFuncGenerator gen(enumDecl, &enumInst, functionNesting);
482 gen.generateAndAppendFunctions(declsToAddAfter);
[af746cc]483}
484
485void ImplementEnumFunc::previsit(const ast::FunctionDecl*) {
[fc1a3e2]486 functionNesting += 1;
[af746cc]487}
488
489void ImplementEnumFunc::postvisit(const ast::FunctionDecl*) {
[fc1a3e2]490 functionNesting -= 1;
[af746cc]491}
492
[fc1a3e2]493} // namespace
[af746cc]494
495void implementEnumFunc(ast::TranslationUnit& translationUnit) {
[fc1a3e2]496 ast::Pass<ImplementEnumFunc>::run(translationUnit);
[af746cc]497}
[fc1a3e2]498
499} // namespace Validate
Note: See TracBrowser for help on using the repository browser.