- Timestamp:
- Jun 13, 2023, 4:33:16 PM (14 months ago)
- Branches:
- master
- Children:
- 5668740, fec8bd1
- Parents:
- 576aadb
- Location:
- src
- Files:
-
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
src/AST/Decl.cpp
r576aadb r8f557161 142 142 bool EnumDecl::valueOf( const Decl * enumerator, long long& value ) const { 143 143 if ( enumValues.empty() ) { 144 long long crntVal = 0;144 Evaluation crntVal = {0, true, true}; // until expression is given, we know to start counting from 0 145 145 for ( const Decl * member : members ) { 146 146 const ObjectDecl* field = strict_dynamic_cast< const ObjectDecl* >( member ); 147 147 if ( field->init ) { 148 148 const SingleInit * init = strict_dynamic_cast< const SingleInit* >( field->init.get() ); 149 auto result= eval( init->value );150 if ( ! result.second) {149 crntVal = eval( init->value ); 150 if ( ! crntVal.isEvaluableInGCC ) { 151 151 SemanticError( init->location, ::toString( "Non-constexpr in initialization of " 152 152 "enumerator: ", field ) ); 153 153 } 154 crntVal = result.first;155 154 } 156 155 if ( enumValues.count( field->name ) != 0 ) { 157 156 SemanticError( location, ::toString( "Enum ", name, " has multiple members with the " "name ", field->name ) ); 158 157 } 159 enumValues[ field->name ] = crntVal; 160 ++crntVal; 158 if (crntVal.hasKnownValue) { 159 enumValues[ field->name ] = crntVal.knownValue; 160 } 161 ++crntVal.knownValue; 161 162 } 162 163 } -
src/Common/Eval.cc
r576aadb r8f557161 96 96 // New AST 97 97 struct EvalNew : public ast::WithShortCircuiting { 98 long long int value = 0; // compose the result of the constant expression 99 bool valid = true; // true => constant expression and value is the result 100 // false => not constant expression, e.g., ++i 101 bool cfavalid = true; // true => constant expression and value computable 102 // false => constant expression but value not computable, e.g., sizeof(int) 98 Evaluation result = { 0, true, true }; 103 99 104 100 void previsit( const ast::Node * ) { visit_children = false; } 105 void postvisit( const ast::Node * ) { cfavalid = valid= false; }101 void postvisit( const ast::Node * ) { result.isEvaluableInGCC = result.hasKnownValue = false; } 106 102 107 103 void postvisit( const ast::UntypedExpr * ) { … … 110 106 111 107 void postvisit( const ast::ConstantExpr * expr ) { // only handle int constants 112 value = expr->intValue(); 108 result.knownValue = expr->intValue(); 109 result.hasKnownValue = true; 110 result.isEvaluableInGCC = true; 113 111 } 114 112 115 113 void postvisit( const ast::SizeofExpr * ) { 116 // do not change valid or value => let C figure it out117 cfavalid = false;114 result.hasKnownValue = false; 115 result.isEvaluableInGCC = true; 118 116 } 119 117 120 118 void postvisit( const ast::AlignofExpr * ) { 121 // do not change valid or value => let C figure it out122 cfavalid = false;119 result.hasKnownValue = false; 120 result.isEvaluableInGCC = true; 123 121 } 124 122 125 123 void postvisit( const ast::OffsetofExpr * ) { 126 // do not change valid or value => let C figure it out127 cfavalid = false;124 result.hasKnownValue = false; 125 result.isEvaluableInGCC = true; 128 126 } 129 127 130 128 void postvisit( const ast::LogicalExpr * expr ) { 131 std::pair<long long int, bool>arg1, arg2;129 Evaluation arg1, arg2; 132 130 arg1 = eval( expr->arg1 ); 133 valid &= arg1.second;134 if ( ! valid) return;131 result.isEvaluableInGCC &= arg1.isEvaluableInGCC; 132 if ( ! result.isEvaluableInGCC ) return; 135 133 arg2 = eval( expr->arg2 ); 136 valid &= arg2.second; 137 if ( ! valid ) return; 134 result.isEvaluableInGCC &= arg2.isEvaluableInGCC; 135 if ( ! result.isEvaluableInGCC ) return; 136 137 result.hasKnownValue &= arg1.hasKnownValue; 138 result.hasKnownValue &= arg2.hasKnownValue; 139 if ( ! result.hasKnownValue ) return; 138 140 139 141 if ( expr->isAnd ) { 140 value = arg1.first && arg2.first;142 result.knownValue = arg1.knownValue && arg2.knownValue; 141 143 } else { 142 value = arg1.first || arg2.first;144 result.knownValue = arg1.knownValue || arg2.knownValue; 143 145 } // if 144 146 } 145 147 146 148 void postvisit( const ast::ConditionalExpr * expr ) { 147 std::pair<long long int, bool>arg1, arg2, arg3;149 Evaluation arg1, arg2, arg3; 148 150 arg1 = eval( expr->arg1 ); 149 valid &= arg1.second;150 if ( ! valid) return;151 result.isEvaluableInGCC &= arg1.isEvaluableInGCC; 152 if ( ! result.isEvaluableInGCC ) return; 151 153 arg2 = eval( expr->arg2 ); 152 valid &= arg2.second;153 if ( ! valid) return;154 result.isEvaluableInGCC &= arg2.isEvaluableInGCC; 155 if ( ! result.isEvaluableInGCC ) return; 154 156 arg3 = eval( expr->arg3 ); 155 valid &= arg3.second; 156 if ( ! valid ) return; 157 158 value = arg1.first ? arg2.first : arg3.first; 157 result.isEvaluableInGCC &= arg3.isEvaluableInGCC; 158 if ( ! result.isEvaluableInGCC ) return; 159 160 result.hasKnownValue &= arg1.hasKnownValue; 161 result.hasKnownValue &= arg2.hasKnownValue; 162 result.hasKnownValue &= arg3.hasKnownValue; 163 if ( ! result.hasKnownValue ) return; 164 165 result.knownValue = arg1.knownValue ? arg2.knownValue : arg3.knownValue; 159 166 } 160 167 161 168 void postvisit( const ast::CastExpr * expr ) { 162 // cfa-cc generates a cast before every constant and many other places, e.g., (int)3, so the cast argument must 163 // be evaluated to get the constant value. 164 auto arg = eval(expr->arg); 165 valid = arg.second; 166 value = arg.first; 167 cfavalid = false; 169 // cfa-cc generates a cast before every constant and many other places, e.g., (int)3, 170 // so we must use the value from the cast argument, even though we lack any basis for evaluating wraparound effects, etc 171 result = eval(expr->arg); 168 172 } 169 173 170 174 void postvisit( const ast::VariableExpr * expr ) { 175 result.hasKnownValue = false; 176 result.isEvaluableInGCC = false; 171 177 if ( const ast::EnumInstType * inst = dynamic_cast<const ast::EnumInstType *>(expr->result.get()) ) { 172 178 if ( const ast::EnumDecl * decl = inst->base ) { 173 if ( decl->valueOf( expr->var, value ) ) { // value filled by valueOf 174 return; 175 } 179 result.isEvaluableInGCC = true; 180 result.hasKnownValue = decl->valueOf( expr->var, result.knownValue ); // result.knownValue filled by valueOf 176 181 } 177 182 } 178 valid = false;179 183 } 180 184 181 185 void postvisit( const ast::ApplicationExpr * expr ) { 182 186 const ast::DeclWithType * function = ast::getFunction(expr); 183 if ( ! function || function->linkage != ast::Linkage::Intrinsic ) { valid = false; return; } 187 if ( ! function || function->linkage != ast::Linkage::Intrinsic ) { 188 result.isEvaluableInGCC = false; 189 result.hasKnownValue = false; 190 return; 191 } 184 192 const std::string & fname = function->name; 185 193 assertf( expr->args.size() == 1 || expr->args.size() == 2, "Intrinsic function with %zd arguments: %s", expr->args.size(), fname.c_str() ); … … 187 195 if ( expr->args.size() == 1 ) { 188 196 // pre/postfix operators ++ and -- => assignment, which is not constant 189 std::pair<long long int, bool>arg1;197 Evaluation arg1; 190 198 arg1 = eval(expr->args.front()); 191 valid &= arg1.second; 192 if ( ! valid ) return; 199 result.isEvaluableInGCC &= arg1.isEvaluableInGCC; 200 if ( ! result.isEvaluableInGCC ) return; 201 202 result.hasKnownValue &= arg1.hasKnownValue; 203 if ( ! result.hasKnownValue ) return; 193 204 194 205 if (fname == "+?") { 195 value = arg1.first;206 result.knownValue = arg1.knownValue; 196 207 } else if (fname == "-?") { 197 value = -arg1.first;208 result.knownValue = -arg1.knownValue; 198 209 } else if (fname == "~?") { 199 value = ~arg1.first;210 result.knownValue = ~arg1.knownValue; 200 211 } else if (fname == "!?") { 201 value = ! arg1.first;212 result.knownValue = ! arg1.knownValue; 202 213 } else { 203 valid = false; 214 result.isEvaluableInGCC = false; 215 result.hasKnownValue = false; 204 216 } // if 205 217 } else { // => expr->args.size() == 2 206 218 // infix assignment operators => assignment, which is not constant 207 std::pair<long long int, bool>arg1, arg2;219 Evaluation arg1, arg2; 208 220 arg1 = eval(expr->args.front()); 209 valid &= arg1.second;210 if ( ! valid) return;221 result.isEvaluableInGCC &= arg1.isEvaluableInGCC; 222 if ( ! result.isEvaluableInGCC ) return; 211 223 arg2 = eval(expr->args.back()); 212 valid &= arg2.second; 213 if ( ! valid ) return; 224 result.isEvaluableInGCC &= arg2.isEvaluableInGCC; 225 if ( ! result.isEvaluableInGCC ) return; 226 227 result.hasKnownValue &= arg1.hasKnownValue; 228 result.hasKnownValue &= arg2.hasKnownValue; 229 if ( ! result.hasKnownValue ) return; 214 230 215 231 if (fname == "?+?") { 216 value = arg1.first + arg2.first;232 result.knownValue = arg1.knownValue + arg2.knownValue; 217 233 } else if (fname == "?-?") { 218 value = arg1.first - arg2.first;234 result.knownValue = arg1.knownValue - arg2.knownValue; 219 235 } else if (fname == "?*?") { 220 value = arg1.first * arg2.first;236 result.knownValue = arg1.knownValue * arg2.knownValue; 221 237 } else if (fname == "?/?") { 222 if ( arg2. first ) value = arg1.first / arg2.first;238 if ( arg2.knownValue ) result.knownValue = arg1.knownValue / arg2.knownValue; 223 239 } else if (fname == "?%?") { 224 if ( arg2. first ) value = arg1.first % arg2.first;240 if ( arg2.knownValue ) result.knownValue = arg1.knownValue % arg2.knownValue; 225 241 } else if (fname == "?<<?") { 226 value = arg1.first << arg2.first;242 result.knownValue = arg1.knownValue << arg2.knownValue; 227 243 } else if (fname == "?>>?") { 228 value = arg1.first >> arg2.first;244 result.knownValue = arg1.knownValue >> arg2.knownValue; 229 245 } else if (fname == "?<?") { 230 value = arg1.first < arg2.first;246 result.knownValue = arg1.knownValue < arg2.knownValue; 231 247 } else if (fname == "?>?") { 232 value = arg1.first > arg2.first;248 result.knownValue = arg1.knownValue > arg2.knownValue; 233 249 } else if (fname == "?<=?") { 234 value = arg1.first <= arg2.first;250 result.knownValue = arg1.knownValue <= arg2.knownValue; 235 251 } else if (fname == "?>=?") { 236 value = arg1.first >= arg2.first;252 result.knownValue = arg1.knownValue >= arg2.knownValue; 237 253 } else if (fname == "?==?") { 238 value = arg1.first == arg2.first;254 result.knownValue = arg1.knownValue == arg2.knownValue; 239 255 } else if (fname == "?!=?") { 240 value = arg1.first != arg2.first;256 result.knownValue = arg1.knownValue != arg2.knownValue; 241 257 } else if (fname == "?&?") { 242 value = arg1.first & arg2.first;258 result.knownValue = arg1.knownValue & arg2.knownValue; 243 259 } else if (fname == "?^?") { 244 value = arg1.first ^ arg2.first;260 result.knownValue = arg1.knownValue ^ arg2.knownValue; 245 261 } else if (fname == "?|?") { 246 value = arg1.first | arg2.first;262 result.knownValue = arg1.knownValue | arg2.knownValue; 247 263 } else { 248 valid = false; 264 result.isEvaluableInGCC = false; 265 result.hasKnownValue = false; 249 266 } 250 267 } // if … … 263 280 } 264 281 265 std::pair<long long int, bool> eval( const ast::Expr * expr ) { 266 ast::Pass<EvalNew> ev; 282 Evaluation eval( const ast::Expr * expr ) { 267 283 if ( expr ) { 268 expr->accept( ev ); 269 return std::make_pair( ev.core.value, ev.core.valid ); 284 285 return ast::Pass<EvalNew>::read(expr); 286 // Evaluation ret = ast::Pass<EvalNew>::read(expr); 287 // ret.knownValue = 777; 288 // return ret; 289 270 290 } else { 271 return std::make_pair( 0, false );291 return { 0, false, false }; 272 292 } 273 293 } -
src/Common/Eval.h
r576aadb r8f557161 23 23 } 24 24 25 struct Evaluation { 26 long long int knownValue; 27 bool hasKnownValue; 28 bool isEvaluableInGCC; 29 }; 30 25 31 /// Evaluates expr as a long long int. 26 32 /// If second is false, expr could not be evaluated. 27 33 std::pair<long long int, bool> eval(const Expression * expr); 28 std::pair<long long int, bool>eval(const ast::Expr * expr);34 Evaluation eval(const ast::Expr * expr); 29 35 30 36 // Local Variables: // -
src/ResolvExpr/CurrentObject.cc
r576aadb r8f557161 689 689 690 690 auto arg = eval( expr ); 691 index = arg.first; 691 assertf( arg.hasKnownValue, "Non-evaluable expression made it to IndexIterator" ); 692 index = arg.knownValue; 692 693 693 694 // if ( auto constExpr = dynamic_cast< const ConstantExpr * >( expr ) ) { … … 728 729 size_t getSize( const Expr * expr ) { 729 730 auto res = eval( expr ); 730 if ( !res. second) {731 if ( !res.hasKnownValue ) { 731 732 SemanticError( location, toString( "Array designator must be a constant expression: ", expr ) ); 732 733 } 733 return res. first;734 return res.knownValue; 734 735 } 735 736 -
src/ResolvExpr/Resolver.cc
r576aadb r8f557161 1341 1341 auto mutAttr = mutate(attr); 1342 1342 mutAttr->params.front() = resolved; 1343 if (! result. second) {1343 if (! result.hasKnownValue) { 1344 1344 SemanticWarning(loc, Warning::GccAttributes, 1345 1345 toCString( name, " priorities must be integers from 0 to 65535 inclusive: ", arg ) ); 1346 1346 } 1347 1347 else { 1348 auto priority = result. first;1348 auto priority = result.knownValue; 1349 1349 if (priority < 101) { 1350 1350 SemanticWarning(loc, Warning::GccAttributes,
Note: See TracChangeset
for help on using the changeset viewer.