[clang] [Clang][WIP] Constant Expressions inside of gcc'asm strings (PR #131003)
via cfe-commits
cfe-commits at lists.llvm.org
Thu Mar 13 10:09:25 PDT 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang-codegen
Author: cor3ntin (cor3ntin)
<details>
<summary>Changes</summary>
Implements GCC's constexpr string ASM extension
https://gcc.gnu.org/onlinedocs/gcc/Asm-constexprs.html
---
Patch is 77.41 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/131003.diff
25 Files Affected:
- (modified) clang/docs/LanguageExtensions.rst (+18)
- (modified) clang/docs/ReleaseNotes.rst (+9)
- (modified) clang/include/clang/AST/Expr.h (+4)
- (modified) clang/include/clang/AST/RecursiveASTVisitor.h (+4-4)
- (modified) clang/include/clang/AST/Stmt.h (+28-32)
- (modified) clang/include/clang/Basic/DiagnosticParseKinds.td (+4-1)
- (modified) clang/include/clang/Basic/DiagnosticSemaKinds.td (+23-13)
- (modified) clang/include/clang/Basic/Features.def (+1)
- (modified) clang/include/clang/Sema/Sema.h (+17-3)
- (modified) clang/lib/AST/ASTImporter.cpp (+6-6)
- (modified) clang/lib/AST/ExprConstant.cpp (+40-11)
- (modified) clang/lib/AST/Stmt.cpp (+78-48)
- (modified) clang/lib/AST/StmtPrinter.cpp (+4-4)
- (modified) clang/lib/AST/StmtProfile.cpp (+4-4)
- (modified) clang/lib/CodeGen/CGStmt.cpp (+9-8)
- (modified) clang/lib/Parse/ParseStmtAsm.cpp (+3-3)
- (modified) clang/lib/Parse/Parser.cpp (+27-14)
- (modified) clang/lib/Sema/SemaDeclCXX.cpp (+72-34)
- (modified) clang/lib/Sema/SemaStmtAsm.cpp (+107-65)
- (modified) clang/lib/Sema/TreeTransform.h (+36-13)
- (modified) clang/lib/Serialization/ASTReaderStmt.cpp (+5-5)
- (modified) clang/lib/Serialization/ASTWriterStmt.cpp (+4-4)
- (added) clang/test/CodeGenCXX/gnu-asm-constexpr.cpp (+38)
- (modified) clang/test/Parser/asm.cpp (+45)
- (added) clang/test/Sema/gnu-asm-constexpr.cpp (+127)
``````````diff
diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst
index f8d1bc9fe2624..a990eefc8eeac 100644
--- a/clang/docs/LanguageExtensions.rst
+++ b/clang/docs/LanguageExtensions.rst
@@ -1958,6 +1958,24 @@ references can be used instead of numeric references.
return -1;
}
+
+Constexpr strings in GNU ASM statememts
+=======================================
+
+In C++11 mode (and greater), Clang supports specifying the template,
+constraints, and clobber strings with a parenthesized constant expression
+producing an object with ``data`` and ``size`` member functions,
+such as ``std::string``.
+
+Query for this feature with ``__has_extension(gnu_asm_constexpr_strings)``.
+
+.. code-block:: c++
+
+ int foo() {
+ asm((std::string_view("nop")) ::: (std::string_view("memory")));
+ }
+
+
Objective-C Features
====================
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 48da5558b3f38..c438b9a997ad8 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -74,6 +74,15 @@ What's New in Clang |release|?
C++ Language Changes
--------------------
+- Similarly to GCC, Clang now supports constant expressions in
+ the strings of a GNU ``asm`` statement.
+
+ .. code-block:: c++
+
+ int foo() {
+ asm((std::string_view("nop")) ::: (std::string_view("memory")));
+ }
+
C++2c Feature Support
^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h
index cfe49acf20b77..28437b5629b00 100644
--- a/clang/include/clang/AST/Expr.h
+++ b/clang/include/clang/AST/Expr.h
@@ -787,6 +787,10 @@ class Expr : public ValueStmt {
const Expr *PtrExpression, ASTContext &Ctx,
EvalResult &Status) const;
+ bool EvaluateCharRangeAsString(APValue &Result, const Expr *SizeExpression,
+ const Expr *PtrExpression, ASTContext &Ctx,
+ EvalResult &Status) const;
+
/// If the current Expr can be evaluated to a pointer to a null-terminated
/// constant string, return the constant string (without the terminating
/// null).
diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h
index fac4c10987157..87a6c22b35ee8 100644
--- a/clang/include/clang/AST/RecursiveASTVisitor.h
+++ b/clang/include/clang/AST/RecursiveASTVisitor.h
@@ -2410,15 +2410,15 @@ DEF_TRAVERSE_DECL(ImplicitConceptSpecializationDecl, {
}
DEF_TRAVERSE_STMT(GCCAsmStmt, {
- TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getAsmString());
+ TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getAsmStringExpr());
for (unsigned I = 0, E = S->getNumInputs(); I < E; ++I) {
- TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getInputConstraintLiteral(I));
+ TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getInputConstraintExpr(I));
}
for (unsigned I = 0, E = S->getNumOutputs(); I < E; ++I) {
- TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getOutputConstraintLiteral(I));
+ TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getOutputConstraintExpr(I));
}
for (unsigned I = 0, E = S->getNumClobbers(); I < E; ++I) {
- TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getClobberStringLiteral(I));
+ TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getClobberExpr(I));
}
// children() iterates over inputExpr and outputExpr.
})
diff --git a/clang/include/clang/AST/Stmt.h b/clang/include/clang/AST/Stmt.h
index 604ac51d478cf..88ae3aeefa869 100644
--- a/clang/include/clang/AST/Stmt.h
+++ b/clang/include/clang/AST/Stmt.h
@@ -3193,7 +3193,7 @@ class AsmStmt : public Stmt {
/// getOutputConstraint - Return the constraint string for the specified
/// output operand. All output constraints are known to be non-empty (either
/// '=' or '+').
- StringRef getOutputConstraint(unsigned i) const;
+ std::string getOutputConstraint(unsigned i) const;
/// isOutputPlusConstraint - Return true if the specified output constraint
/// is a "+" constraint (which is both an input and an output) or false if it
@@ -3214,14 +3214,14 @@ class AsmStmt : public Stmt {
/// getInputConstraint - Return the specified input constraint. Unlike output
/// constraints, these can be empty.
- StringRef getInputConstraint(unsigned i) const;
+ std::string getInputConstraint(unsigned i) const;
const Expr *getInputExpr(unsigned i) const;
//===--- Other ---===//
unsigned getNumClobbers() const { return NumClobbers; }
- StringRef getClobber(unsigned i) const;
+ std::string getClobber(unsigned i) const;
static bool classof(const Stmt *T) {
return T->getStmtClass() == GCCAsmStmtClass ||
@@ -3302,21 +3302,20 @@ class GCCAsmStmt : public AsmStmt {
friend class ASTStmtReader;
SourceLocation RParenLoc;
- StringLiteral *AsmStr;
+ Expr *AsmStr;
// FIXME: If we wanted to, we could allocate all of these in one big array.
- StringLiteral **Constraints = nullptr;
- StringLiteral **Clobbers = nullptr;
+ Expr **Constraints = nullptr;
+ Expr **Clobbers = nullptr;
IdentifierInfo **Names = nullptr;
unsigned NumLabels = 0;
public:
GCCAsmStmt(const ASTContext &C, SourceLocation asmloc, bool issimple,
bool isvolatile, unsigned numoutputs, unsigned numinputs,
- IdentifierInfo **names, StringLiteral **constraints, Expr **exprs,
- StringLiteral *asmstr, unsigned numclobbers,
- StringLiteral **clobbers, unsigned numlabels,
- SourceLocation rparenloc);
+ IdentifierInfo **names, Expr **constraints, Expr **exprs,
+ Expr *asmstr, unsigned numclobbers, Expr **clobbers,
+ unsigned numlabels, SourceLocation rparenloc);
/// Build an empty inline-assembly statement.
explicit GCCAsmStmt(EmptyShell Empty) : AsmStmt(GCCAsmStmtClass, Empty) {}
@@ -3326,9 +3325,11 @@ class GCCAsmStmt : public AsmStmt {
//===--- Asm String Analysis ---===//
- const StringLiteral *getAsmString() const { return AsmStr; }
- StringLiteral *getAsmString() { return AsmStr; }
- void setAsmString(StringLiteral *E) { AsmStr = E; }
+ const Expr *getAsmStringExpr() const { return AsmStr; }
+ Expr *getAsmStringExpr() { return AsmStr; }
+ void setAsmString(Expr *E) { AsmStr = E; }
+
+ std::string getAsmString() const;
/// AsmStringPiece - this is part of a decomposed asm string specification
/// (for use with the AnalyzeAsmString function below). An asm string is
@@ -3397,14 +3398,12 @@ class GCCAsmStmt : public AsmStmt {
return {};
}
- StringRef getOutputConstraint(unsigned i) const;
+ std::string getOutputConstraint(unsigned i) const;
- const StringLiteral *getOutputConstraintLiteral(unsigned i) const {
- return Constraints[i];
- }
- StringLiteral *getOutputConstraintLiteral(unsigned i) {
+ const Expr *getOutputConstraintExpr(unsigned i) const {
return Constraints[i];
}
+ Expr *getOutputConstraintExpr(unsigned i) { return Constraints[i]; }
Expr *getOutputExpr(unsigned i);
@@ -3425,12 +3424,12 @@ class GCCAsmStmt : public AsmStmt {
return {};
}
- StringRef getInputConstraint(unsigned i) const;
+ std::string getInputConstraint(unsigned i) const;
- const StringLiteral *getInputConstraintLiteral(unsigned i) const {
+ const Expr *getInputConstraintExpr(unsigned i) const {
return Constraints[i + NumOutputs];
}
- StringLiteral *getInputConstraintLiteral(unsigned i) {
+ Expr *getInputConstraintExpr(unsigned i) {
return Constraints[i + NumOutputs];
}
@@ -3441,6 +3440,8 @@ class GCCAsmStmt : public AsmStmt {
return const_cast<GCCAsmStmt*>(this)->getInputExpr(i);
}
+ static std::string ExtractStringFromGCCAsmStmtComponent(const Expr *E);
+
//===--- Labels ---===//
bool isAsmGoto() const {
@@ -3489,12 +3490,9 @@ class GCCAsmStmt : public AsmStmt {
private:
void setOutputsAndInputsAndClobbers(const ASTContext &C,
IdentifierInfo **Names,
- StringLiteral **Constraints,
- Stmt **Exprs,
- unsigned NumOutputs,
- unsigned NumInputs,
- unsigned NumLabels,
- StringLiteral **Clobbers,
+ Expr **Constraints, Stmt **Exprs,
+ unsigned NumOutputs, unsigned NumInputs,
+ unsigned NumLabels, Expr **Clobbers,
unsigned NumClobbers);
public:
@@ -3505,12 +3503,10 @@ class GCCAsmStmt : public AsmStmt {
/// This returns -1 if the operand name is invalid.
int getNamedOperand(StringRef SymbolicName) const;
- StringRef getClobber(unsigned i) const;
+ std::string getClobber(unsigned i) const;
- StringLiteral *getClobberStringLiteral(unsigned i) { return Clobbers[i]; }
- const StringLiteral *getClobberStringLiteral(unsigned i) const {
- return Clobbers[i];
- }
+ Expr *getClobberExpr(unsigned i) { return Clobbers[i]; }
+ const Expr *getClobberExpr(unsigned i) const { return Clobbers[i]; }
SourceLocation getBeginLoc() const LLVM_READONLY { return AsmLoc; }
SourceLocation getEndLoc() const LLVM_READONLY { return RParenLoc; }
diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td
index 092a55f9e9e0c..4dc956f7ae6f7 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -336,7 +336,10 @@ def warn_cxx20_compat_label_end_of_compound_statement : Warning<
def err_address_of_label_outside_fn : Error<
"use of address-of-label extension outside of a function body">;
def err_asm_operand_wide_string_literal : Error<
- "cannot use %select{unicode|wide|an empty}0 string literal in 'asm'">;
+ "cannot use %select{unicode|wide}0 string literal in 'asm'">;
+
+def err_asm_expected_string : Error<
+ "expected string literal %select{or parenthesized constant expression |}0in 'asm'">;
def err_expected_selector_for_method : Error<
"expected selector for Objective-C method">;
def err_expected_property_name : Error<"expected property name">;
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 4bdbb797c2b86..2e8db1a2249e4 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -1663,23 +1663,30 @@ def err_static_assert_requirement_failed : Error<
"static assertion failed due to requirement '%0'%select{: %2|}1">;
def note_expr_evaluates_to : Note<
"expression evaluates to '%0 %1 %2'">;
-def err_static_assert_invalid_message : Error<
- "the message in a static assertion must be a string literal or an "
+
+
+def subst_user_defined_msg : TextSubstitution<
+ "%select{the message|the expression}0 in "
+ "%select{a static assertion|this asm operand}0">;
+
+def err_user_defined_msg_invalid : Error<
+ "%sub{subst_user_defined_msg}0 must be a string literal or an "
"object with 'data()' and 'size()' member functions">;
-def err_static_assert_missing_member_function : Error<
- "the message object in this static assertion is missing %select{"
+def err_user_defined_msg_missing_member_function : Error<
+ "the %select{message|string}0 object in "
+ "%select{this static assertion|this asm operand}0 is missing %select{"
"a 'size()' member function|"
"a 'data()' member function|"
- "'data()' and 'size()' member functions}0">;
-def err_static_assert_invalid_mem_fn_ret_ty : Error<
- "the message in a static assertion must have a '%select{size|data}0()' member "
- "function returning an object convertible to '%select{std::size_t|const char *}0'">;
-def warn_static_assert_message_constexpr : Warning<
- "the message in this static assertion is not a "
- "constant expression">,
+ "'data()' and 'size()' member functions}1">;
+def err_user_defined_msg_invalid_mem_fn_ret_ty : Error<
+ "%sub{subst_user_defined_msg}0 must have a '%select{size|data}1()' member "
+ "function returning an object convertible to '%select{std::size_t|const char *}1'">;
+def warn_user_defined_msg_constexpr : Warning<
+ "%select{the message|the expression}0 in "
+ "%select{this static assertion|this asm operand}0 is not a constant expression">,
DefaultError, InGroup<DiagGroup<"invalid-static-assert-message">>;
-def err_static_assert_message_constexpr : Error<
- "the message in a static assertion must be produced by a "
+def err_user_defined_msg_constexpr : Error<
+ "%sub{subst_user_defined_msg}0 must be produced by a "
"constant expression">;
def warn_consteval_if_always_true : Warning<
@@ -9514,6 +9521,9 @@ def warn_redefine_extname_not_applied : Warning<
// inline asm.
let CategoryName = "Inline Assembly Issue" in {
+ def err_asm_operand_empty_string : Error<
+ "cannot use an empty string literal in 'asm'">;
+
def err_asm_pmf_through_constraint_not_permitted
: Error<"cannot pass a pointer-to-member through register-constrained "
"inline assembly parameter">;
diff --git a/clang/include/clang/Basic/Features.def b/clang/include/clang/Basic/Features.def
index 92b1705d15227..05ce214935fad 100644
--- a/clang/include/clang/Basic/Features.def
+++ b/clang/include/clang/Basic/Features.def
@@ -306,6 +306,7 @@ EXTENSION(statement_attributes_with_gnu_syntax, true)
EXTENSION(gnu_asm, LangOpts.GNUAsm)
EXTENSION(gnu_asm_goto_with_outputs, LangOpts.GNUAsm)
EXTENSION(gnu_asm_goto_with_outputs_full, LangOpts.GNUAsm)
+EXTENSION(gnu_asm_constexpr_strings, LangOpts.GNUAsm && LangOpts.CPlusPlus11)
EXTENSION(matrix_types, LangOpts.MatrixTypes)
EXTENSION(matrix_types_scalar_division, true)
EXTENSION(cxx_attributes_on_using_declarations, LangOpts.CPlusPlus11)
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index c034de0e633da..4043699912423 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -5585,9 +5585,15 @@ class Sema final : public SemaBase {
void ActOnFinishDelayedCXXMethodDeclaration(Scope *S, Decl *Method);
void ActOnFinishDelayedMemberInitializers(Decl *Record);
- bool EvaluateStaticAssertMessageAsString(Expr *Message, std::string &Result,
- ASTContext &Ctx,
- bool ErrorOnInvalidMessage);
+ enum class StringEvaluationContext { StaticAssert = 0, Asm = 1 };
+
+ bool EvaluateAsString(Expr *Message, APValue &Result, ASTContext &Ctx,
+ StringEvaluationContext EvalContext,
+ bool ErrorOnInvalidMessage);
+ bool EvaluateAsString(Expr *Message, std::string &Result, ASTContext &Ctx,
+ StringEvaluationContext EvalContext,
+ bool ErrorOnInvalidMessage);
+
Decl *ActOnStaticAssertDeclaration(SourceLocation StaticAssertLoc,
Expr *AssertExpr, Expr *AssertMessageExpr,
SourceLocation RParenLoc);
@@ -11040,6 +11046,7 @@ class Sema final : public SemaBase {
///@{
public:
+ ExprResult ActOnGCCAsmStmtString(Expr *Stm, bool ForAsmLabel);
StmtResult ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
bool IsVolatile, unsigned NumOutputs,
unsigned NumInputs, IdentifierInfo **Names,
@@ -15328,6 +15335,13 @@ void Sema::PragmaStack<Sema::AlignPackInfo>::Act(SourceLocation PragmaLocation,
PragmaMsStackAction Action,
llvm::StringRef StackSlotLabel,
AlignPackInfo Value);
+
+inline const StreamingDiagnostic &
+operator<<(const StreamingDiagnostic &DB, Sema::StringEvaluationContext Ctx) {
+ DB << llvm::to_underlying(Ctx);
+ return DB;
+}
+
} // end namespace clang
#endif
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp
index 82180486f3c7c..1b507761ddf70 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -6821,25 +6821,25 @@ ExpectedStmt ASTNodeImporter::VisitGCCAsmStmt(GCCAsmStmt *S) {
Names.push_back(ToII);
}
- SmallVector<StringLiteral *, 4> Clobbers;
+ SmallVector<Expr *, 4> Clobbers;
for (unsigned I = 0, E = S->getNumClobbers(); I != E; I++) {
- if (auto ClobberOrErr = import(S->getClobberStringLiteral(I)))
+ if (auto ClobberOrErr = import(S->getClobberExpr(I)))
Clobbers.push_back(*ClobberOrErr);
else
return ClobberOrErr.takeError();
}
- SmallVector<StringLiteral *, 4> Constraints;
+ SmallVector<Expr *, 4> Constraints;
for (unsigned I = 0, E = S->getNumOutputs(); I != E; I++) {
- if (auto OutputOrErr = import(S->getOutputConstraintLiteral(I)))
+ if (auto OutputOrErr = import(S->getOutputConstraintExpr(I)))
Constraints.push_back(*OutputOrErr);
else
return OutputOrErr.takeError();
}
for (unsigned I = 0, E = S->getNumInputs(); I != E; I++) {
- if (auto InputOrErr = import(S->getInputConstraintLiteral(I)))
+ if (auto InputOrErr = import(S->getInputConstraintExpr(I)))
Constraints.push_back(*InputOrErr);
else
return InputOrErr.takeError();
@@ -6861,7 +6861,7 @@ ExpectedStmt ASTNodeImporter::VisitGCCAsmStmt(GCCAsmStmt *S) {
ExpectedSLoc AsmLocOrErr = import(S->getAsmLoc());
if (!AsmLocOrErr)
return AsmLocOrErr.takeError();
- auto AsmStrOrErr = import(S->getAsmString());
+ auto AsmStrOrErr = import(S->getAsmStringExpr());
if (!AsmStrOrErr)
return AsmStrOrErr.takeError();
ExpectedSLoc RParenLocOrErr = import(S->getRParenLoc());
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index f8e8aaddbfdbd..7803b1026aab9 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -17928,10 +17928,12 @@ std::optional<std::string> Expr::tryEvaluateString(ASTContext &Ctx) const {
return {};
}
-bool Expr::EvaluateCharRangeAsString(std::string &Result,
- const Expr *SizeExpression,
- const Expr *PtrExpression, ASTContext &Ctx,
- EvalResult &Status) const {
+template <typename T>
+static bool EvaluateCharRangeAsStringImpl(const Expr *, T &Result,
+ const Expr *SizeExpression,
+ const Expr *PtrExpression,
+ ASTContext &Ctx,
+ Expr::EvalResult &Status) {
LValue String;
EvalInfo Info(Ctx, Status, EvalInfo::EM_ConstantExpression);
Info.InConstantContext = true;
@@ -17943,6 +17945,13 @@ bool Expr::EvaluateCharRangeAsString(std::string &Result,
uint64_t Size = SizeValue.getZExtValue();
+ // FIXME: better protect against invalid or excessive sizes
+ if constexpr (std::is_same_v<APValue, T>)
+ Result = APValue(APValue::UninitArray{}, Size, Size);
+ else {
+ if (Size < Result.max_size())
+ Result.reserve(Size);
+ }
if (!::EvaluatePointer(PtrExpression, String, Info))
return false;
@@ -17953,18 +17962,38 @@ bool Expr::EvaluateCharRangeAsString(std::string &Result,
Char))
return false;
- APSInt C = Char.getInt();
- Result.push_back(static_cast<char>(C.getExtValue()));
+ if constexpr (std::is_same_v<APValue, T>) {
+ Result.getArrayInitializedElt(I) = std::move(Char);
+ } else {
+ APSInt C = Char.getInt();
+
+ assert(C.getBitWidth() <= 8 &&
+ "string element not representable in char");
+
+ Result.push_back(static_cast<char>(C.getExtValue()));
+ }
+
if (!HandleLValueArrayAdjustment(Info, PtrExpression, String, CharTy, 1))
return false;
}
- if (!Scope.destroy())
- return false;
- if (!CheckMemoryLeaks(Info))
- return false;
+ return Scope.destroy() && CheckMemoryLeaks(Info);
+}
- return true;
+bool Expr::EvaluateCharRangeAsString(std::string &Result,
+ const Expr *SizeExpression,
+ const Expr *PtrExpression, ASTContext &Ctx,
+ ...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/131003
More information about the cfe-commits
mailing list