|
5 | 5 |
|
6 | 6 | #include <clang/AST/DeclTemplate.h> |
7 | 7 | #include <clang/AST/ExprCXX.h> |
| 8 | +#include <clang/AST/ExprConcepts.h> |
8 | 9 | #include <clang/AST/Mangle.h> |
9 | 10 | #include <clang/AST/ParentMapContext.h> |
10 | 11 | #include <clang/Basic/SourceManager.h> |
| 12 | +#include <clang/Lex/Lexer.h> |
11 | 13 | #include <clang/Sema/Initialization.h> |
12 | 14 | #include <clang/Sema/Sema.h> |
13 | 15 | #include <llvm/Support/ErrorHandling.h> |
@@ -111,6 +113,67 @@ bool IsBuiltinConstantP(const clang::Expr *expr) { |
111 | 113 | return false; |
112 | 114 | } |
113 | 115 |
|
| 116 | +bool IsRustConstEvaluableExpr(const clang::Expr *expr) { |
| 117 | + expr = expr->IgnoreParenImpCasts(); |
| 118 | + if (clang::isa<clang::IntegerLiteral, clang::ConceptSpecializationExpr>( |
| 119 | + expr)) { |
| 120 | + return true; |
| 121 | + } |
| 122 | + if (auto *trait = clang::dyn_cast<clang::UnaryExprOrTypeTraitExpr>(expr)) { |
| 123 | + return trait->getKind() == clang::UnaryExprOrTypeTrait::UETT_SizeOf; |
| 124 | + } |
| 125 | + if (auto *unary = clang::dyn_cast<clang::UnaryOperator>(expr)) { |
| 126 | + return unary->getOpcode() == clang::UO_LNot && |
| 127 | + IsRustConstEvaluableExpr(unary->getSubExpr()); |
| 128 | + } |
| 129 | + if (auto *binary = clang::dyn_cast<clang::BinaryOperator>(expr)) { |
| 130 | + return (binary->isEqualityOp() || binary->isRelationalOp()) && |
| 131 | + IsRustConstEvaluableExpr(binary->getLHS()) && |
| 132 | + IsRustConstEvaluableExpr(binary->getRHS()); |
| 133 | + } |
| 134 | + return false; |
| 135 | +} |
| 136 | + |
| 137 | +std::string GetEscapedCharLiteral(char character) { |
| 138 | + switch (character) { |
| 139 | + case '"': |
| 140 | + return "\\\""; |
| 141 | + case '\'': |
| 142 | + return "\\'"; |
| 143 | + case '\\': |
| 144 | + return "\\\\"; |
| 145 | + case '\n': |
| 146 | + return "\\n"; |
| 147 | + case '\r': |
| 148 | + return "\\r"; |
| 149 | + case '\t': |
| 150 | + return "\\t"; |
| 151 | + case '\0': |
| 152 | + return "\\0"; |
| 153 | + } |
| 154 | + auto uc = static_cast<unsigned char>(character); |
| 155 | + if (uc < 0x20 || uc >= 0x7F) { |
| 156 | + return std::format("\\x{:02x}", uc); |
| 157 | + } |
| 158 | + return std::string(1, character); |
| 159 | +} |
| 160 | + |
| 161 | +std::string GetAssertMessageAsString(const clang::Expr *expr, |
| 162 | + const clang::ASTContext &ctx) { |
| 163 | + auto text = clang::Lexer::getSourceText( |
| 164 | + clang::CharSourceRange::getTokenRange(expr->getSourceRange()), |
| 165 | + ctx.getSourceManager(), ctx.getLangOpts()); |
| 166 | + std::string message = R"(, ")"; |
| 167 | + for (char c : text) { |
| 168 | + // Doubled so that assert! does not read them as a format placeholder. |
| 169 | + if (c == '{' || c == '}') { |
| 170 | + message += c; |
| 171 | + } |
| 172 | + message += GetEscapedCharLiteral(c); |
| 173 | + } |
| 174 | + return message + '"'; |
| 175 | +} |
| 176 | + |
114 | 177 | bool IsComparisonWithNullOp(const clang::BinaryOperator *expr) { |
115 | 178 | if (!expr->isComparisonOp()) { |
116 | 179 | return false; |
|
0 commit comments