[clang] [Clang][WIP] Constant Expressions inside of gcc'asm strings (PR #131003)

via cfe-commits cfe-commits at lists.llvm.org
Wed Mar 12 11:42:38 PDT 2025


https://github.com/cor3ntin updated https://github.com/llvm/llvm-project/pull/131003

>From 84508166a9784701dad659881bf75f9764e53f54 Mon Sep 17 00:00:00 2001
From: Corentin Jabot <corentinjabot at gmail.com>
Date: Wed, 12 Mar 2025 12:23:14 +0100
Subject: [PATCH 1/2] [Clang][WIP] Constant Expressions inside of gcc'asm
 strings

Implements GCC's constexpr string ASM extension
https://gcc.gnu.org/onlinedocs/gcc/Asm-constexprs.html
---
 clang/include/clang/AST/Expr.h                |   5 +
 clang/include/clang/AST/RecursiveASTVisitor.h |   8 +-
 clang/include/clang/AST/Stmt.h                |  50 +++---
 .../clang/Basic/DiagnosticParseKinds.td       |   5 +-
 .../clang/Basic/DiagnosticSemaKinds.td        |  36 +++--
 clang/include/clang/Sema/Sema.h               |  25 ++-
 clang/lib/AST/ASTImporter.cpp                 |  12 +-
 clang/lib/AST/ExprConstant.cpp                |  83 ++++++----
 clang/lib/AST/Stmt.cpp                        | 103 ++++++++----
 clang/lib/AST/StmtPrinter.cpp                 |  21 ++-
 clang/lib/AST/StmtProfile.cpp                 |   8 +-
 clang/lib/CodeGen/CGStmt.cpp                  |  16 +-
 clang/lib/Parse/ParseStmtAsm.cpp              |   2 +-
 clang/lib/Parse/Parser.cpp                    |  37 +++--
 clang/lib/Sema/SemaDeclCXX.cpp                |  99 ++++++++----
 clang/lib/Sema/SemaStmtAsm.cpp                | 147 +++++++++++-------
 clang/lib/Sema/TreeTransform.h                |  50 ++++--
 clang/lib/Serialization/ASTReaderStmt.cpp     |  10 +-
 clang/lib/Serialization/ASTWriterStmt.cpp     |   8 +-
 19 files changed, 473 insertions(+), 252 deletions(-)

diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h
index cfe49acf20b77..7f9e50dfe78bd 100644
--- a/clang/include/clang/AST/Expr.h
+++ b/clang/include/clang/AST/Expr.h
@@ -787,6 +787,11 @@ 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..7bf0a6911c515 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,20 +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,
+             IdentifierInfo **names, Expr **constraints, Expr **exprs,
+             Expr *asmstr, unsigned numclobbers,
+             Expr **clobbers, unsigned numlabels,
              SourceLocation rparenloc);
 
   /// Build an empty inline-assembly statement.
@@ -3326,9 +3326,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,12 +3399,12 @@ class GCCAsmStmt : public AsmStmt {
     return {};
   }
 
-  StringRef getOutputConstraint(unsigned i) const;
+  std::string getOutputConstraint(unsigned i) const;
 
-  const StringLiteral *getOutputConstraintLiteral(unsigned i) const {
+  const Expr *getOutputConstraintExpr(unsigned i) const {
     return Constraints[i];
   }
-  StringLiteral *getOutputConstraintLiteral(unsigned i) {
+  Expr *getOutputConstraintExpr(unsigned i) {
     return Constraints[i];
   }
 
@@ -3425,12 +3427,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 +3443,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 +3493,12 @@ class GCCAsmStmt : public AsmStmt {
 private:
   void setOutputsAndInputsAndClobbers(const ASTContext &C,
                                       IdentifierInfo **Names,
-                                      StringLiteral **Constraints,
+                                      Expr **Constraints,
                                       Stmt **Exprs,
                                       unsigned NumOutputs,
                                       unsigned NumInputs,
                                       unsigned NumLabels,
-                                      StringLiteral **Clobbers,
+                                      Expr **Clobbers,
                                       unsigned NumClobbers);
 
 public:
@@ -3505,10 +3509,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 {
+  Expr *getClobberExpr(unsigned i) { return Clobbers[i]; }
+  const Expr *getClobberExpr(unsigned i) const {
     return Clobbers[i];
   }
 
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/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index c034de0e633da..e1b1083675612 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -5585,9 +5585,18 @@ 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 +11049,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 +15338,15 @@ 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..86fe8554cba85 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -17928,43 +17928,70 @@ 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 {
-  LValue String;
-  EvalInfo Info(Ctx, Status, EvalInfo::EM_ConstantExpression);
-  Info.InConstantContext = true;
+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;
 
-  FullExpressionRAII Scope(Info);
-  APSInt SizeValue;
-  if (!::EvaluateInteger(SizeExpression, SizeValue, Info))
-    return false;
+    FullExpressionRAII Scope(Info);
+    APSInt SizeValue;
+    if (!::EvaluateInteger(SizeExpression, SizeValue, Info))
+      return false;
 
-  uint64_t Size = SizeValue.getZExtValue();
+    uint64_t Size = SizeValue.getZExtValue();
 
-  if (!::EvaluatePointer(PtrExpression, String, Info))
-    return false;
+    if constexpr(std::is_same_v<APValue, T>)
+        Result = APValue(APValue::UninitArray{}, Size, Size);
+    //else
+    //    Result.reserve(Size);
 
-  QualType CharTy = PtrExpression->getType()->getPointeeType();
-  for (uint64_t I = 0; I < Size; ++I) {
-    APValue Char;
-    if (!handleLValueToRValueConversion(Info, PtrExpression, CharTy, String,
-                                        Char))
+    if (!::EvaluatePointer(PtrExpression, String, Info))
+      return false;
+
+    QualType CharTy = PtrExpression->getType()->getPointeeType();
+    for (uint64_t I = 0; I < Size; ++I) {
+      APValue Char;
+      if (!handleLValueToRValueConversion(Info, PtrExpression, CharTy, String,
+                                          Char))
+        return false;
+
+      if constexpr(std::is_same_v<APValue, T>) {
+          Result.getArrayInitializedElt(I) = std::move(Char);
+      }
+      else {
+          APSInt C = Char.getInt();
+          Result.push_back(static_cast<char>(C.getExtValue()));
+      }
+
+      if (!HandleLValueArrayAdjustment(Info, PtrExpression, String, CharTy, 1))
+        return false;
+    }
+    if (!Scope.destroy())
       return false;
 
-    APSInt C = Char.getInt();
-    Result.push_back(static_cast<char>(C.getExtValue()));
-    if (!HandleLValueArrayAdjustment(Info, PtrExpression, String, CharTy, 1))
+    if (!CheckMemoryLeaks(Info))
       return false;
-  }
-  if (!Scope.destroy())
-    return false;
 
-  if (!CheckMemoryLeaks(Info))
-    return false;
+    return true;
+}
 
-  return true;
+
+bool Expr::EvaluateCharRangeAsString(std::string &Result,
+                                     const Expr *SizeExpression,
+                                     const Expr *PtrExpression, ASTContext &Ctx,
+                                     EvalResult &Status) const {
+    return EvaluateCharRangeAsStringImpl(this, Result, SizeExpression, PtrExpression, Ctx, Status);
+}
+
+bool Expr::EvaluateCharRangeAsString(APValue &Result,
+                               const Expr *SizeExpression,
+                               const Expr *PtrExpression, ASTContext &Ctx,
+                                EvalResult &Status) const {
+    return EvaluateCharRangeAsStringImpl(this, Result, SizeExpression, PtrExpression, Ctx, Status);
 }
 
 bool Expr::tryEvaluateStrLen(uint64_t &Result, ASTContext &Ctx) const {
diff --git a/clang/lib/AST/Stmt.cpp b/clang/lib/AST/Stmt.cpp
index c8ff2ecea20cc..6e0d95714b641 100644
--- a/clang/lib/AST/Stmt.cpp
+++ b/clang/lib/AST/Stmt.cpp
@@ -455,11 +455,11 @@ std::string AsmStmt::generateAsmString(const ASTContext &C) const {
   llvm_unreachable("unknown asm statement kind!");
 }
 
-StringRef AsmStmt::getOutputConstraint(unsigned i) const {
+std::string AsmStmt::getOutputConstraint(unsigned i) const {
   if (const auto *gccAsmStmt = dyn_cast<GCCAsmStmt>(this))
     return gccAsmStmt->getOutputConstraint(i);
   if (const auto *msAsmStmt = dyn_cast<MSAsmStmt>(this))
-    return msAsmStmt->getOutputConstraint(i);
+    return msAsmStmt->getOutputConstraint(i).str();
   llvm_unreachable("unknown asm statement kind!");
 }
 
@@ -471,11 +471,11 @@ const Expr *AsmStmt::getOutputExpr(unsigned i) const {
   llvm_unreachable("unknown asm statement kind!");
 }
 
-StringRef AsmStmt::getInputConstraint(unsigned i) const {
+std::string AsmStmt::getInputConstraint(unsigned i) const {
   if (const auto *gccAsmStmt = dyn_cast<GCCAsmStmt>(this))
     return gccAsmStmt->getInputConstraint(i);
   if (const auto *msAsmStmt = dyn_cast<MSAsmStmt>(this))
-    return msAsmStmt->getInputConstraint(i);
+    return msAsmStmt->getInputConstraint(i).str();
   llvm_unreachable("unknown asm statement kind!");
 }
 
@@ -487,11 +487,11 @@ const Expr *AsmStmt::getInputExpr(unsigned i) const {
   llvm_unreachable("unknown asm statement kind!");
 }
 
-StringRef AsmStmt::getClobber(unsigned i) const {
+std::string AsmStmt::getClobber(unsigned i) const {
   if (const auto *gccAsmStmt = dyn_cast<GCCAsmStmt>(this))
     return gccAsmStmt->getClobber(i);
   if (const auto *msAsmStmt = dyn_cast<MSAsmStmt>(this))
-    return msAsmStmt->getClobber(i);
+    return msAsmStmt->getClobber(i).str();
   llvm_unreachable("unknown asm statement kind!");
 }
 
@@ -510,8 +510,31 @@ char GCCAsmStmt::AsmStringPiece::getModifier() const {
   return isLetter(Str[0]) ? Str[0] : '\0';
 }
 
-StringRef GCCAsmStmt::getClobber(unsigned i) const {
-  return getClobberStringLiteral(i)->getString();
+std::string GCCAsmStmt::ExtractStringFromGCCAsmStmtComponent(const Expr* E) {
+  if(auto* SL = llvm::dyn_cast<StringLiteral>(E))
+    return SL->getString().str();
+  assert(E->getDependence() == ExprDependence::None && "cannot extract a string from a dependent expression");
+  auto* CE = cast<ConstantExpr>(E);
+  APValue Res = CE->getAPValueResult();
+  assert(Res.isArray() && "expected an array");
+
+  std::string Out;
+  Out.reserve(Res.getArraySize());
+  for(unsigned I = 0; I < Res.getArraySize(); ++I) {
+    APValue C = Res.getArrayInitializedElt(I);
+    assert(C.isInt());
+    auto Ch = static_cast<char>(C.getInt().getExtValue());
+    Out.push_back(Ch);
+  }
+  return Out;
+}
+
+std::string GCCAsmStmt::getAsmString() const {
+  return ExtractStringFromGCCAsmStmtComponent(getAsmStringExpr());
+}
+
+std::string GCCAsmStmt::getClobber(unsigned i) const {
+  return ExtractStringFromGCCAsmStmtComponent(getClobberExpr(i));
 }
 
 Expr *GCCAsmStmt::getOutputExpr(unsigned i) {
@@ -521,8 +544,8 @@ Expr *GCCAsmStmt::getOutputExpr(unsigned i) {
 /// getOutputConstraint - Return the constraint string for the specified
 /// output operand.  All output constraints are known to be non-empty (either
 /// '=' or '+').
-StringRef GCCAsmStmt::getOutputConstraint(unsigned i) const {
-  return getOutputConstraintLiteral(i)->getString();
+std::string GCCAsmStmt::getOutputConstraint(unsigned i) const {
+  return ExtractStringFromGCCAsmStmtComponent(getOutputConstraintExpr(i));
 }
 
 Expr *GCCAsmStmt::getInputExpr(unsigned i) {
@@ -543,18 +566,18 @@ StringRef GCCAsmStmt::getLabelName(unsigned i) const {
 
 /// getInputConstraint - Return the specified input constraint.  Unlike output
 /// constraints, these can be empty.
-StringRef GCCAsmStmt::getInputConstraint(unsigned i) const {
-  return getInputConstraintLiteral(i)->getString();
+std::string GCCAsmStmt::getInputConstraint(unsigned i) const {
+  return ExtractStringFromGCCAsmStmtComponent(getInputConstraintExpr(i));
 }
 
 void GCCAsmStmt::setOutputsAndInputsAndClobbers(const ASTContext &C,
                                                 IdentifierInfo **Names,
-                                                StringLiteral **Constraints,
+                                                Expr **Constraints,
                                                 Stmt **Exprs,
                                                 unsigned NumOutputs,
                                                 unsigned NumInputs,
                                                 unsigned NumLabels,
-                                                StringLiteral **Clobbers,
+                                                Expr **Clobbers,
                                                 unsigned NumClobbers) {
   this->NumOutputs = NumOutputs;
   this->NumInputs = NumInputs;
@@ -573,11 +596,11 @@ void GCCAsmStmt::setOutputsAndInputsAndClobbers(const ASTContext &C,
 
   unsigned NumConstraints = NumOutputs + NumInputs;
   C.Deallocate(this->Constraints);
-  this->Constraints = new (C) StringLiteral*[NumConstraints];
+  this->Constraints = new (C) Expr*[NumConstraints];
   std::copy(Constraints, Constraints + NumConstraints, this->Constraints);
 
   C.Deallocate(this->Clobbers);
-  this->Clobbers = new (C) StringLiteral*[NumClobbers];
+  this->Clobbers = new (C) Expr*[NumClobbers];
   std::copy(Clobbers, Clobbers + NumClobbers, this->Clobbers);
 }
 
@@ -609,9 +632,10 @@ int GCCAsmStmt::getNamedOperand(StringRef SymbolicName) const {
 /// true, otherwise return false.
 unsigned GCCAsmStmt::AnalyzeAsmString(SmallVectorImpl<AsmStringPiece>&Pieces,
                                 const ASTContext &C, unsigned &DiagOffs) const {
-  StringRef Str = getAsmString()->getString();
-  const char *StrStart = Str.begin();
-  const char *StrEnd = Str.end();
+
+  std::string Str = getAsmString();
+  const char *StrStart = Str.data();
+  const char *StrEnd = Str.data() + Str.size();
   const char *CurPtr = StrStart;
 
   // "Simple" inline asms have no constraints or operands, just convert the asm
@@ -739,15 +763,21 @@ unsigned GCCAsmStmt::AnalyzeAsmString(SmallVectorImpl<AsmStringPiece>&Pieces,
 
       // Str contains "x4" (Operand without the leading %).
       std::string Str(Begin, CurPtr - Begin);
-
       // (BeginLoc, EndLoc) represents the range of the operand we are currently
       // processing. Unlike Str, the range includes the leading '%'.
-      SourceLocation BeginLoc = getAsmString()->getLocationOfByte(
-          Percent - StrStart, SM, LO, TI, &LastAsmStringToken,
-          &LastAsmStringOffset);
-      SourceLocation EndLoc = getAsmString()->getLocationOfByte(
-          CurPtr - StrStart, SM, LO, TI, &LastAsmStringToken,
-          &LastAsmStringOffset);
+      SourceLocation BeginLoc, EndLoc;
+      if(auto* SL = dyn_cast<StringLiteral>(getAsmStringExpr())) {
+        BeginLoc = SL->getLocationOfByte(
+            Percent - StrStart, SM, LO, TI, &LastAsmStringToken,
+            &LastAsmStringOffset);
+        EndLoc = SL->getLocationOfByte(
+            CurPtr - StrStart, SM, LO, TI, &LastAsmStringToken,
+            &LastAsmStringOffset);
+      }
+      else {
+        BeginLoc = getAsmStringExpr()->getBeginLoc();
+        EndLoc = getAsmStringExpr()->getEndLoc();
+      }
 
       Pieces.emplace_back(N, std::move(Str), BeginLoc, EndLoc);
       continue;
@@ -778,12 +808,19 @@ unsigned GCCAsmStmt::AnalyzeAsmString(SmallVectorImpl<AsmStringPiece>&Pieces,
 
       // (BeginLoc, EndLoc) represents the range of the operand we are currently
       // processing. Unlike Str, the range includes the leading '%'.
-      SourceLocation BeginLoc = getAsmString()->getLocationOfByte(
+      SourceLocation BeginLoc, EndLoc;
+      if(auto* SL = dyn_cast<StringLiteral>(getAsmStringExpr())) {
+        BeginLoc = SL->getLocationOfByte(
           Percent - StrStart, SM, LO, TI, &LastAsmStringToken,
           &LastAsmStringOffset);
-      SourceLocation EndLoc = getAsmString()->getLocationOfByte(
+        EndLoc = SL->getLocationOfByte(
           NameEnd + 1 - StrStart, SM, LO, TI, &LastAsmStringToken,
           &LastAsmStringOffset);
+      }
+      else {
+        BeginLoc = getAsmStringExpr()->getBeginLoc();
+        EndLoc = getAsmStringExpr()->getEndLoc();
+      }
 
       Pieces.emplace_back(N, std::move(Str), BeginLoc, EndLoc);
 
@@ -863,9 +900,9 @@ void MSAsmStmt::setInputExpr(unsigned i, Expr *E) {
 GCCAsmStmt::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,
+                       Expr **constraints, Expr **exprs,
+                       Expr *asmstr, unsigned numclobbers,
+                       Expr **clobbers, unsigned numlabels,
                        SourceLocation rparenloc)
     : AsmStmt(GCCAsmStmtClass, asmloc, issimple, isvolatile, numoutputs,
               numinputs, numclobbers),
@@ -879,10 +916,10 @@ GCCAsmStmt::GCCAsmStmt(const ASTContext &C, SourceLocation asmloc,
   std::copy(exprs, exprs + NumExprs, Exprs);
 
   unsigned NumConstraints = NumOutputs + NumInputs;
-  Constraints = new (C) StringLiteral*[NumConstraints];
+  Constraints = new (C) Expr*[NumConstraints];
   std::copy(constraints, constraints + NumConstraints, Constraints);
 
-  Clobbers = new (C) StringLiteral*[NumClobbers];
+  Clobbers = new (C) Expr*[NumClobbers];
   std::copy(clobbers, clobbers + NumClobbers, Clobbers);
 }
 
diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp
index e0063ec5f25eb..c8623225b486c 100644
--- a/clang/lib/AST/StmtPrinter.cpp
+++ b/clang/lib/AST/StmtPrinter.cpp
@@ -497,6 +497,19 @@ void StmtPrinter::VisitReturnStmt(ReturnStmt *Node) {
   if (Policy.IncludeNewlines) OS << NL;
 }
 
+static void PrintGCCAsmString(raw_ostream &OS, Expr*E) {
+  if(E->getDependence()) {
+    OS << "<<dependent expr>>";
+    return;
+  }
+
+  std::string Str = GCCAsmStmt::ExtractStringFromGCCAsmStmtComponent(E);
+  llvm::SmallVector<char> Out;
+  // FIXME: Unify with StringLiteral::outputString
+  EscapeStringForDiagnostic(Str, Out);
+  OS << '"' << Out << '"';
+}
+
 void StmtPrinter::VisitGCCAsmStmt(GCCAsmStmt *Node) {
   Indent() << "asm ";
 
@@ -507,7 +520,7 @@ void StmtPrinter::VisitGCCAsmStmt(GCCAsmStmt *Node) {
     OS << "goto ";
 
   OS << "(";
-  VisitStringLiteral(Node->getAsmString());
+  PrintGCCAsmString(OS, Node->getAsmStringExpr());
 
   // Outputs
   if (Node->getNumOutputs() != 0 || Node->getNumInputs() != 0 ||
@@ -524,7 +537,7 @@ void StmtPrinter::VisitGCCAsmStmt(GCCAsmStmt *Node) {
       OS << "] ";
     }
 
-    VisitStringLiteral(Node->getOutputConstraintLiteral(i));
+    PrintGCCAsmString(OS, Node->getOutputConstraintExpr(i));
     OS << " (";
     Visit(Node->getOutputExpr(i));
     OS << ")";
@@ -545,7 +558,7 @@ void StmtPrinter::VisitGCCAsmStmt(GCCAsmStmt *Node) {
       OS << "] ";
     }
 
-    VisitStringLiteral(Node->getInputConstraintLiteral(i));
+    PrintGCCAsmString(OS, Node->getInputConstraintExpr(i));
     OS << " (";
     Visit(Node->getInputExpr(i));
     OS << ")";
@@ -559,7 +572,7 @@ void StmtPrinter::VisitGCCAsmStmt(GCCAsmStmt *Node) {
     if (i != 0)
       OS << ", ";
 
-    VisitStringLiteral(Node->getClobberStringLiteral(i));
+    PrintGCCAsmString(OS, Node->getClobberExpr(i));
   }
 
   // Labels
diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp
index bf72de3854f4b..96852858b3b9e 100644
--- a/clang/lib/AST/StmtProfile.cpp
+++ b/clang/lib/AST/StmtProfile.cpp
@@ -328,20 +328,20 @@ void StmtProfiler::VisitGCCAsmStmt(const GCCAsmStmt *S) {
   VisitStmt(S);
   ID.AddBoolean(S->isVolatile());
   ID.AddBoolean(S->isSimple());
-  VisitStringLiteral(S->getAsmString());
+  VisitExpr(S->getAsmStringExpr());
   ID.AddInteger(S->getNumOutputs());
   for (unsigned I = 0, N = S->getNumOutputs(); I != N; ++I) {
     ID.AddString(S->getOutputName(I));
-    VisitStringLiteral(S->getOutputConstraintLiteral(I));
+    VisitExpr(S->getOutputConstraintExpr(I));
   }
   ID.AddInteger(S->getNumInputs());
   for (unsigned I = 0, N = S->getNumInputs(); I != N; ++I) {
     ID.AddString(S->getInputName(I));
-    VisitStringLiteral(S->getInputConstraintLiteral(I));
+    VisitExpr(S->getInputConstraintExpr(I));
   }
   ID.AddInteger(S->getNumClobbers());
   for (unsigned I = 0, N = S->getNumClobbers(); I != N; ++I)
-    VisitStringLiteral(S->getClobberStringLiteral(I));
+    VisitExpr(S->getClobberExpr(I));
   ID.AddInteger(S->getNumLabels());
   for (auto *L : S->labels())
     VisitDecl(L->getLabel());
diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp
index 99b6f563d7c82..6ef9625f75118 100644
--- a/clang/lib/CodeGen/CGStmt.cpp
+++ b/clang/lib/CodeGen/CGStmt.cpp
@@ -2586,9 +2586,11 @@ static void UpdateAsmCallInst(llvm::CallBase &Result, bool HasSideEffect,
 
   // Slap the source location of the inline asm into a !srcloc metadata on the
   // call.
-  if (const auto *gccAsmStmt = dyn_cast<GCCAsmStmt>(&S))
-    Result.setMetadata("srcloc",
-                       getAsmSrcLocInfo(gccAsmStmt->getAsmString(), CGF));
+  if (const auto *gccAsmStmt = dyn_cast<GCCAsmStmt>(&S)) {
+    if(const StringLiteral* SL = dyn_cast<StringLiteral>(gccAsmStmt->getAsmStringExpr()))
+      Result.setMetadata("srcloc",
+                         getAsmSrcLocInfo(SL, CGF));
+  }
   else {
     // At least put the line number on MS inline asm blobs.
     llvm::Constant *Loc =
@@ -2705,9 +2707,9 @@ static void EmitHipStdParUnsupportedAsm(CodeGenFunction *CGF,
                                         const AsmStmt &S) {
   constexpr auto Name = "__ASM__hipstdpar_unsupported";
 
-  StringRef Asm;
+  std::string Asm;
   if (auto GCCAsm = dyn_cast<GCCAsmStmt>(&S))
-    Asm = GCCAsm->getAsmString()->getString();
+    Asm = GCCAsm->getAsmString();
 
   auto &Ctx = CGF->CGM.getLLVMContext();
 
@@ -3050,7 +3052,7 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
 
   // Clobbers
   for (unsigned i = 0, e = S.getNumClobbers(); i != e; i++) {
-    StringRef Clobber = S.getClobber(i);
+    std::string Clobber = S.getClobber(i);
 
     if (Clobber == "memory")
       ReadOnly = ReadNone = false;
@@ -3071,7 +3073,7 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
         if (Constraints.find("=&A") != std::string::npos)
           continue;
         std::string::size_type position1 =
-            Constraints.find("={" + Clobber.str() + "}");
+            Constraints.find("={" + Clobber + "}");
         if (position1 != std::string::npos) {
           Constraints.insert(position1 + 1, "&");
           continue;
diff --git a/clang/lib/Parse/ParseStmtAsm.cpp b/clang/lib/Parse/ParseStmtAsm.cpp
index 04c3a8700c10c..94144225ff406 100644
--- a/clang/lib/Parse/ParseStmtAsm.cpp
+++ b/clang/lib/Parse/ParseStmtAsm.cpp
@@ -809,7 +809,7 @@ StmtResult Parser::ParseAsmStatement(bool &msAsm) {
       ConsumeToken();
     }
     // Parse the asm-string list for clobbers if present.
-    if (!AteExtraColon && isTokenStringLiteral()) {
+    if (!AteExtraColon && (isTokenStringLiteral() || Tok.is(tok::l_paren))) {
       while (true) {
         ExprResult Clobber(ParseAsmStringLiteral(/*ForAsmLabel*/ false));
 
diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp
index 0710542f5e938..baf264c808820 100644
--- a/clang/lib/Parse/Parser.cpp
+++ b/clang/lib/Parse/Parser.cpp
@@ -1668,28 +1668,37 @@ void Parser::ParseKNRParamDeclarations(Declarator &D) {
 ///         string-literal
 ///
 ExprResult Parser::ParseAsmStringLiteral(bool ForAsmLabel) {
-  if (!isTokenStringLiteral()) {
-    Diag(Tok, diag::err_expected_string_literal)
-      << /*Source='in...'*/0 << "'asm'";
-    return ExprError();
-  }
 
-  ExprResult AsmString(ParseStringLiteralExpression());
-  if (!AsmString.isInvalid()) {
+  ExprResult AsmString;
+  if(isTokenStringLiteral()) {
+    AsmString = ParseStringLiteralExpression();
+    if(AsmString.isInvalid())
+      return AsmString;
+
     const auto *SL = cast<StringLiteral>(AsmString.get());
     if (!SL->isOrdinary()) {
       Diag(Tok, diag::err_asm_operand_wide_string_literal)
-        << SL->isWide()
-        << SL->getSourceRange();
+      << SL->isWide()
+      << SL->getSourceRange();
       return ExprError();
     }
-    if (ForAsmLabel && SL->getString().empty()) {
-      Diag(Tok, diag::err_asm_operand_wide_string_literal)
-          << 2 /* an empty */ << SL->getSourceRange();
+  }
+  else if(!ForAsmLabel && getLangOpts().CPlusPlus11 && Tok.is(tok::l_paren)) {
+    ParenParseOption ExprType = SimpleExpr;
+    SourceLocation   RParenLoc;
+    ParsedType CastTy;
+
+    AsmString = ParseParenExpression(ExprType, true/*stopIfCastExpr*/,
+                                   false, CastTy, RParenLoc);
+    if(!AsmString.isUsable())
       return ExprError();
-    }
   }
-  return AsmString;
+  else {
+    Diag(Tok, diag::err_asm_expected_string)
+      << /*and expression=*/(getLangOpts().CPlusPlus11? 0 : 1);
+  }
+
+  return Actions.ActOnGCCAsmStmtString(AsmString.get(), ForAsmLabel);
 }
 
 /// ParseSimpleAsm
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 96aac7871db1e..332099bbbd437 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -17261,17 +17261,34 @@ void Sema::DiagnoseStaticAssertDetails(const Expr *E) {
   }
 }
 
-bool Sema::EvaluateStaticAssertMessageAsString(Expr *Message,
-                                               std::string &Result,
-                                               ASTContext &Ctx,
-                                               bool ErrorOnInvalidMessage) {
+template <typename ResultType>
+static bool EvaluateAsStringImpl(Sema & SemaRef,
+                            Expr *Message,
+                            ResultType &Result, ASTContext &Ctx,
+                            Sema::StringEvaluationContext EvalContext,
+                            bool ErrorOnInvalidMessage) {
+
   assert(Message);
   assert(!Message->isTypeDependent() && !Message->isValueDependent() &&
          "can't evaluate a dependant static assert message");
 
   if (const auto *SL = dyn_cast<StringLiteral>(Message)) {
     assert(SL->isUnevaluated() && "expected an unevaluated string");
-    Result.assign(SL->getString().begin(), SL->getString().end());
+    if constexpr(std::is_same_v<APValue, ResultType>) {
+        Result = APValue(APValue::UninitArray{}, SL->getLength(), SL->getLength());
+        const ConstantArrayType *CAT = SemaRef.getASTContext().getAsConstantArrayType(SL->getType());
+        assert(CAT && "string literal isn't an array");
+        QualType CharType = CAT->getElementType();
+        llvm::APSInt Value(SemaRef.getASTContext().getTypeSize(CharType),
+                     CharType->isUnsignedIntegerType());
+        for(unsigned I = 0; I < SL->getLength(); I++) {
+            Value = SL->getCodeUnit(I);
+            Result.getArrayInitializedElt(I) = APValue(Value);
+        }
+    }
+    else {
+        Result.assign(SL->getString().begin(), SL->getString().end());
+    }
     return true;
   }
 
@@ -17279,15 +17296,15 @@ bool Sema::EvaluateStaticAssertMessageAsString(Expr *Message,
   QualType T = Message->getType().getNonReferenceType();
   auto *RD = T->getAsCXXRecordDecl();
   if (!RD) {
-    Diag(Loc, diag::err_static_assert_invalid_message);
+    SemaRef.Diag(Loc, diag::err_user_defined_msg_invalid) << EvalContext;
     return false;
   }
 
   auto FindMember = [&](StringRef Member, bool &Empty,
                         bool Diag = false) -> std::optional<LookupResult> {
-    DeclarationName DN = PP.getIdentifierInfo(Member);
-    LookupResult MemberLookup(*this, DN, Loc, Sema::LookupMemberName);
-    LookupQualifiedName(MemberLookup, RD);
+    DeclarationName DN = SemaRef.PP.getIdentifierInfo(Member);
+    LookupResult MemberLookup(SemaRef, DN, Loc, Sema::LookupMemberName);
+    SemaRef.LookupQualifiedName(MemberLookup, RD);
     Empty = MemberLookup.empty();
     OverloadCandidateSet Candidates(MemberLookup.getNameLoc(),
                                     OverloadCandidateSet::CSK_Normal);
@@ -17300,7 +17317,8 @@ bool Sema::EvaluateStaticAssertMessageAsString(Expr *Message,
   std::optional<LookupResult> SizeMember = FindMember("size", SizeNotFound);
   std::optional<LookupResult> DataMember = FindMember("data", DataNotFound);
   if (SizeNotFound || DataNotFound) {
-    Diag(Loc, diag::err_static_assert_missing_member_function)
+    SemaRef.Diag(Loc, diag::err_user_defined_msg_missing_member_function)
+        << EvalContext
         << ((SizeNotFound && DataNotFound) ? 2
             : SizeNotFound                 ? 0
                                            : 1);
@@ -17316,47 +17334,49 @@ bool Sema::EvaluateStaticAssertMessageAsString(Expr *Message,
   }
 
   auto BuildExpr = [&](LookupResult &LR) {
-    ExprResult Res = BuildMemberReferenceExpr(
+    ExprResult Res = SemaRef.BuildMemberReferenceExpr(
         Message, Message->getType(), Message->getBeginLoc(), false,
         CXXScopeSpec(), SourceLocation(), nullptr, LR, nullptr, nullptr);
     if (Res.isInvalid())
       return ExprError();
-    Res = BuildCallExpr(nullptr, Res.get(), Loc, {}, Loc, nullptr, false, true);
+    Res = SemaRef.BuildCallExpr(nullptr, Res.get(), Loc, {}, Loc, nullptr, false, true);
     if (Res.isInvalid())
       return ExprError();
     if (Res.get()->isTypeDependent() || Res.get()->isValueDependent())
       return ExprError();
-    return TemporaryMaterializationConversion(Res.get());
+    return SemaRef.TemporaryMaterializationConversion(Res.get());
   };
 
   ExprResult SizeE = BuildExpr(*SizeMember);
   ExprResult DataE = BuildExpr(*DataMember);
 
-  QualType SizeT = Context.getSizeType();
+  QualType SizeT = SemaRef.Context.getSizeType();
   QualType ConstCharPtr =
-      Context.getPointerType(Context.getConstType(Context.CharTy));
+      SemaRef.Context.getPointerType(SemaRef.Context.getConstType(SemaRef.Context.CharTy));
 
   ExprResult EvaluatedSize =
       SizeE.isInvalid() ? ExprError()
-                        : BuildConvertedConstantExpression(
-                              SizeE.get(), SizeT, CCEK_StaticAssertMessageSize);
+                        : SemaRef.BuildConvertedConstantExpression(
+                              SizeE.get(), SizeT, Sema::CCEK_StaticAssertMessageSize);
   if (EvaluatedSize.isInvalid()) {
-    Diag(Loc, diag::err_static_assert_invalid_mem_fn_ret_ty) << /*size*/ 0;
+    SemaRef.Diag(Loc, diag::err_user_defined_msg_invalid_mem_fn_ret_ty)
+            << EvalContext << /*size*/ 0;
     return false;
   }
 
   ExprResult EvaluatedData =
       DataE.isInvalid()
           ? ExprError()
-          : BuildConvertedConstantExpression(DataE.get(), ConstCharPtr,
-                                             CCEK_StaticAssertMessageData);
+          : SemaRef.BuildConvertedConstantExpression(DataE.get(), ConstCharPtr,
+                                             Sema::CCEK_StaticAssertMessageData);
   if (EvaluatedData.isInvalid()) {
-    Diag(Loc, diag::err_static_assert_invalid_mem_fn_ret_ty) << /*data*/ 1;
+    SemaRef.Diag(Loc, diag::err_user_defined_msg_invalid_mem_fn_ret_ty)
+            << EvalContext << /*data*/ 1;
     return false;
   }
 
   if (!ErrorOnInvalidMessage &&
-      Diags.isIgnored(diag::warn_static_assert_message_constexpr, Loc))
+      SemaRef.Diags.isIgnored(diag::warn_user_defined_msg_constexpr, Loc))
     return true;
 
   Expr::EvalResult Status;
@@ -17365,16 +17385,30 @@ bool Sema::EvaluateStaticAssertMessageAsString(Expr *Message,
   if (!Message->EvaluateCharRangeAsString(Result, EvaluatedSize.get(),
                                           EvaluatedData.get(), Ctx, Status) ||
       !Notes.empty()) {
-    Diag(Message->getBeginLoc(),
-         ErrorOnInvalidMessage ? diag::err_static_assert_message_constexpr
-                               : diag::warn_static_assert_message_constexpr);
+    SemaRef.Diag(Message->getBeginLoc(),
+         ErrorOnInvalidMessage ? diag::err_user_defined_msg_constexpr
+                               : diag::warn_user_defined_msg_constexpr)
+            << EvalContext;
     for (const auto &Note : Notes)
-      Diag(Note.first, Note.second);
+      SemaRef.Diag(Note.first, Note.second);
     return !ErrorOnInvalidMessage;
   }
   return true;
 }
 
+bool Sema::EvaluateAsString(Expr *Message, APValue &Result, ASTContext &Ctx,
+                            StringEvaluationContext EvalContext,
+                            bool ErrorOnInvalidMessage) {
+    return EvaluateAsStringImpl(*this, Message, Result, Ctx, EvalContext, ErrorOnInvalidMessage);
+
+}
+
+bool Sema::EvaluateAsString(Expr *Message, std::string &Result, ASTContext &Ctx,
+                            StringEvaluationContext EvalContext,
+                            bool ErrorOnInvalidMessage) {
+    return EvaluateAsStringImpl(*this, Message, Result, Ctx, EvalContext, ErrorOnInvalidMessage);
+}
+
 Decl *Sema::BuildStaticAssertDeclaration(SourceLocation StaticAssertLoc,
                                          Expr *AssertExpr, Expr *AssertMessage,
                                          SourceLocation RParenLoc,
@@ -17420,8 +17454,9 @@ Decl *Sema::BuildStaticAssertDeclaration(SourceLocation StaticAssertLoc,
     // the message is grammatically valid without evaluating it.
     if (!Failed && AssertMessage && Cond.getBoolValue()) {
       std::string Str;
-      EvaluateStaticAssertMessageAsString(AssertMessage, Str, Context,
-                                          /*ErrorOnInvalidMessage=*/false);
+      EvaluateAsString(AssertMessage, Str, Context,
+                        StringEvaluationContext::StaticAssert,
+                       /*ErrorOnInvalidMessage=*/false);
     }
 
     // CWG2518
@@ -17436,10 +17471,10 @@ Decl *Sema::BuildStaticAssertDeclaration(SourceLocation StaticAssertLoc,
       bool HasMessage = AssertMessage;
       if (AssertMessage) {
         std::string Str;
-        HasMessage =
-            EvaluateStaticAssertMessageAsString(
-                AssertMessage, Str, Context, /*ErrorOnInvalidMessage=*/true) ||
-            !Str.empty();
+        HasMessage = EvaluateAsString(AssertMessage, Str, Context,
+                                      StringEvaluationContext::StaticAssert,
+                                      /*ErrorOnInvalidMessage=*/true) ||
+                     !Str.empty();
         Msg << Str;
       }
       Expr *InnerCond = nullptr;
diff --git a/clang/lib/Sema/SemaStmtAsm.cpp b/clang/lib/Sema/SemaStmtAsm.cpp
index a0b203fbdfec2..e168f57f8f303 100644
--- a/clang/lib/Sema/SemaStmtAsm.cpp
+++ b/clang/lib/Sema/SemaStmtAsm.cpp
@@ -17,6 +17,7 @@
 #include "clang/Lex/Preprocessor.h"
 #include "clang/Sema/Initialization.h"
 #include "clang/Sema/Lookup.h"
+#include "clang/Sema/Ownership.h"
 #include "clang/Sema/Scope.h"
 #include "clang/Sema/ScopeInfo.h"
 #include "llvm/ADT/ArrayRef.h"
@@ -203,15 +204,15 @@ static StringRef extractRegisterName(const Expr *Expression,
 // clobbers list. If there's a conflict, returns the location of the
 // conflicted clobber, else returns nullptr
 static SourceLocation
-getClobberConflictLocation(MultiExprArg Exprs, StringLiteral **Constraints,
-                           StringLiteral **Clobbers, int NumClobbers,
+getClobberConflictLocation(MultiExprArg Exprs, Expr **Constraints,
+                           Expr **Clobbers, int NumClobbers,
                            unsigned NumLabels,
                            const TargetInfo &Target, ASTContext &Cont) {
   llvm::StringSet<> InOutVars;
   // Collect all the input and output registers from the extended asm
   // statement in order to check for conflicts with the clobber list
   for (unsigned int i = 0; i < Exprs.size() - NumLabels; ++i) {
-    StringRef Constraint = Constraints[i]->getString();
+    std::string Constraint = GCCAsmStmt::ExtractStringFromGCCAsmStmtComponent(Constraints[i]);
     StringRef InOutReg = Target.getConstraintRegister(
         Constraint, extractRegisterName(Exprs[i], Target));
     if (InOutReg != "")
@@ -220,7 +221,7 @@ getClobberConflictLocation(MultiExprArg Exprs, StringLiteral **Constraints,
   // Check for each item in the clobber list if it conflicts with the input
   // or output
   for (int i = 0; i < NumClobbers; ++i) {
-    StringRef Clobber = Clobbers[i]->getString();
+    std::string Clobber = GCCAsmStmt::ExtractStringFromGCCAsmStmtComponent(Clobbers[i]);
     // We only check registers, therefore we don't check cc and memory
     // clobbers
     if (Clobber == "cc" || Clobber == "memory" || Clobber == "unwind")
@@ -233,6 +234,36 @@ getClobberConflictLocation(MultiExprArg Exprs, StringLiteral **Constraints,
   return SourceLocation();
 }
 
+ExprResult Sema::ActOnGCCAsmStmtString(Expr* Expr, bool ForAsmLabel) {
+  if(!Expr)
+    return ExprError();
+
+  if(auto* SL = dyn_cast<StringLiteral>(Expr)) {
+    assert(SL->isOrdinary());
+    if (ForAsmLabel && SL->getString().empty()) {
+      Diag(Expr->getBeginLoc(), diag::err_asm_operand_empty_string)
+        << SL->getSourceRange();
+    }
+    return SL;
+  }
+  if(DiagnoseUnexpandedParameterPack(Expr))
+    return ExprError();
+  if(Expr->getDependence() != ExprDependence::None)
+    return Expr;
+  APValue V;
+  if(!EvaluateAsString(Expr, V, getASTContext(), StringEvaluationContext::Asm,
+                        /*ErrorOnInvalid=*/true))
+    return ExprError();
+
+  if (ForAsmLabel && V.getArrayInitializedElts() == 0) {
+    Diag(Expr->getBeginLoc(), diag::err_asm_operand_empty_string);
+  }
+
+  ConstantExpr* Res = ConstantExpr::Create(getASTContext(), Expr, ConstantResultStorageKind::APValue);
+  Res->SetResult(V, getASTContext());
+  return Res;
+}
+
 StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
                                  bool IsVolatile, unsigned NumOutputs,
                                  unsigned NumInputs, IdentifierInfo **Names,
@@ -241,38 +272,44 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
                                  unsigned NumLabels,
                                  SourceLocation RParenLoc) {
   unsigned NumClobbers = clobbers.size();
-  StringLiteral **Constraints =
-    reinterpret_cast<StringLiteral**>(constraints.data());
-  StringLiteral *AsmString = cast<StringLiteral>(asmString);
-  StringLiteral **Clobbers = reinterpret_cast<StringLiteral**>(clobbers.data());
 
   SmallVector<TargetInfo::ConstraintInfo, 4> OutputConstraintInfos;
 
-  // The parser verifies that there is a string literal here.
-  assert(AsmString->isOrdinary());
-
   FunctionDecl *FD = dyn_cast<FunctionDecl>(getCurLexicalContext());
   llvm::StringMap<bool> FeatureMap;
   Context.getFunctionFeatureMap(FeatureMap, FD);
 
-  for (unsigned i = 0; i != NumOutputs; i++) {
-    StringLiteral *Literal = Constraints[i];
-    assert(Literal->isOrdinary());
+  auto CreateGCCAsmStmt = [&] {
+    return new (Context)
+    GCCAsmStmt(Context, AsmLoc, IsSimple, IsVolatile, NumOutputs,
+               NumInputs, Names, constraints.data(), Exprs.data(), asmString,
+               NumClobbers, clobbers.data(), NumLabels, RParenLoc);
+  };
+
+  if(asmString->getDependence() != ExprDependence::None
+     || llvm::any_of(constraints, [] (Expr* E) {
+        return E->getDependence() != ExprDependence::None;
+      })
+     || llvm::any_of(clobbers, [] (Expr* E) {
+        return E->getDependence() != ExprDependence::None;
+     }))
+  return CreateGCCAsmStmt();
 
+  for (unsigned i = 0; i != NumOutputs; i++) {
+    Expr* Constraint = constraints[i];
     StringRef OutputName;
     if (Names[i])
       OutputName = Names[i]->getName();
 
-    TargetInfo::ConstraintInfo Info(Literal->getString(), OutputName);
+    std::string ConstraintStr = GCCAsmStmt::ExtractStringFromGCCAsmStmtComponent(Constraint);
+
+    TargetInfo::ConstraintInfo Info(ConstraintStr, OutputName);
     if (!Context.getTargetInfo().validateOutputConstraint(Info) &&
         !(LangOpts.HIPStdPar && LangOpts.CUDAIsDevice)) {
-      targetDiag(Literal->getBeginLoc(),
+      targetDiag(Constraint->getBeginLoc(),
                  diag::err_asm_invalid_output_constraint)
           << Info.getConstraintStr();
-      return new (Context)
-          GCCAsmStmt(Context, AsmLoc, IsSimple, IsVolatile, NumOutputs,
-                     NumInputs, Names, Constraints, Exprs.data(), AsmString,
-                     NumClobbers, Clobbers, NumLabels, RParenLoc);
+      return CreateGCCAsmStmt();
     }
 
     ExprResult ER = CheckPlaceholderExpr(Exprs[i]);
@@ -335,35 +372,30 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
 
     unsigned Size = Context.getTypeSize(OutputExpr->getType());
     if (!Context.getTargetInfo().validateOutputSize(
-            FeatureMap, Literal->getString(), Size)) {
+            FeatureMap,  GCCAsmStmt::ExtractStringFromGCCAsmStmtComponent(Constraint), Size)) {
       targetDiag(OutputExpr->getBeginLoc(), diag::err_asm_invalid_output_size)
           << Info.getConstraintStr();
-      return new (Context)
-          GCCAsmStmt(Context, AsmLoc, IsSimple, IsVolatile, NumOutputs,
-                     NumInputs, Names, Constraints, Exprs.data(), AsmString,
-                     NumClobbers, Clobbers, NumLabels, RParenLoc);
+      return CreateGCCAsmStmt();
     }
   }
 
   SmallVector<TargetInfo::ConstraintInfo, 4> InputConstraintInfos;
 
   for (unsigned i = NumOutputs, e = NumOutputs + NumInputs; i != e; i++) {
-    StringLiteral *Literal = Constraints[i];
-    assert(Literal->isOrdinary());
+    Expr *Constraint = constraints[i];
 
     StringRef InputName;
     if (Names[i])
       InputName = Names[i]->getName();
 
-    TargetInfo::ConstraintInfo Info(Literal->getString(), InputName);
+    std::string ConstraintStr = GCCAsmStmt::ExtractStringFromGCCAsmStmtComponent(Constraint);
+
+    TargetInfo::ConstraintInfo Info(ConstraintStr, InputName);
     if (!Context.getTargetInfo().validateInputConstraint(OutputConstraintInfos,
                                                          Info)) {
-      targetDiag(Literal->getBeginLoc(), diag::err_asm_invalid_input_constraint)
+      targetDiag(Constraint->getBeginLoc(), diag::err_asm_invalid_input_constraint)
           << Info.getConstraintStr();
-      return new (Context)
-          GCCAsmStmt(Context, AsmLoc, IsSimple, IsVolatile, NumOutputs,
-                     NumInputs, Names, Constraints, Exprs.data(), AsmString,
-                     NumClobbers, Clobbers, NumLabels, RParenLoc);
+      return CreateGCCAsmStmt();
     }
 
     ExprResult ER = CheckPlaceholderExpr(Exprs[i]);
@@ -449,7 +481,7 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
 
     unsigned Size = Context.getTypeSize(Ty);
     if (!Context.getTargetInfo().validateInputSize(FeatureMap,
-                                                   Literal->getString(), Size))
+                                                   ConstraintStr, Size))
       return targetDiag(InputExpr->getBeginLoc(),
                         diag::err_asm_invalid_input_size)
              << Info.getConstraintStr();
@@ -459,46 +491,45 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
 
   // Check that the clobbers are valid.
   for (unsigned i = 0; i != NumClobbers; i++) {
-    StringLiteral *Literal = Clobbers[i];
-    assert(Literal->isOrdinary());
+    Expr *ClobberExpr = clobbers[i];
 
-    StringRef Clobber = Literal->getString();
+    std::string Clobber = GCCAsmStmt::ExtractStringFromGCCAsmStmtComponent(ClobberExpr);
 
     if (!Context.getTargetInfo().isValidClobber(Clobber)) {
-      targetDiag(Literal->getBeginLoc(), diag::err_asm_unknown_register_name)
+      targetDiag(ClobberExpr->getBeginLoc(), diag::err_asm_unknown_register_name)
           << Clobber;
       return new (Context)
           GCCAsmStmt(Context, AsmLoc, IsSimple, IsVolatile, NumOutputs,
-                     NumInputs, Names, Constraints, Exprs.data(), AsmString,
-                     NumClobbers, Clobbers, NumLabels, RParenLoc);
+                     NumInputs, Names, constraints.data(), Exprs.data(), asmString,
+                     NumClobbers, clobbers.data(), NumLabels, RParenLoc);
     }
 
     if (Clobber == "unwind") {
-      UnwindClobberLoc = Literal->getBeginLoc();
+      UnwindClobberLoc = ClobberExpr->getBeginLoc();
     }
   }
 
   // Using unwind clobber and asm-goto together is not supported right now.
   if (UnwindClobberLoc && NumLabels > 0) {
     targetDiag(*UnwindClobberLoc, diag::err_asm_unwind_and_goto);
-    return new (Context)
-        GCCAsmStmt(Context, AsmLoc, IsSimple, IsVolatile, NumOutputs, NumInputs,
-                   Names, Constraints, Exprs.data(), AsmString, NumClobbers,
-                   Clobbers, NumLabels, RParenLoc);
+    return CreateGCCAsmStmt();
   }
 
-  GCCAsmStmt *NS =
-    new (Context) GCCAsmStmt(Context, AsmLoc, IsSimple, IsVolatile, NumOutputs,
-                             NumInputs, Names, Constraints, Exprs.data(),
-                             AsmString, NumClobbers, Clobbers, NumLabels,
-                             RParenLoc);
+  GCCAsmStmt *NS = CreateGCCAsmStmt();
   // Validate the asm string, ensuring it makes sense given the operands we
   // have.
+
+  auto GetLocation = [this](const Expr* Str, unsigned Offset) {
+    if(auto* SL = dyn_cast<StringLiteral>(Str))
+      return getLocationOfStringLiteralByte(SL, Offset);
+    return Str->getBeginLoc();
+  };
+
   SmallVector<GCCAsmStmt::AsmStringPiece, 8> Pieces;
   unsigned DiagOffs;
   if (unsigned DiagID = NS->AnalyzeAsmString(Pieces, Context, DiagOffs)) {
-    targetDiag(getLocationOfStringLiteralByte(AsmString, DiagOffs), DiagID)
-        << AsmString->getSourceRange();
+    targetDiag(GetLocation(asmString, DiagOffs), DiagID)
+        << asmString->getSourceRange();
     return NS;
   }
 
@@ -529,7 +560,7 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
     }
 
     // Now that we have the right indexes go ahead and check.
-    StringLiteral *Literal = Constraints[ConstraintIdx];
+    Expr *Constraint = constraints[ConstraintIdx];
     const Type *Ty = Exprs[ConstraintIdx]->getType().getTypePtr();
     if (Ty->isDependentType() || Ty->isIncompleteType())
       continue;
@@ -537,7 +568,7 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
     unsigned Size = Context.getTypeSize(Ty);
     std::string SuggestedModifier;
     if (!Context.getTargetInfo().validateConstraintModifier(
-            Literal->getString(), Piece.getModifier(), Size,
+            GCCAsmStmt::ExtractStringFromGCCAsmStmtComponent(Constraint), Piece.getModifier(), Size,
             SuggestedModifier)) {
       targetDiag(Exprs[ConstraintIdx]->getBeginLoc(),
                  diag::warn_asm_mismatched_size_modifier);
@@ -546,8 +577,10 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
         auto B = targetDiag(Piece.getRange().getBegin(),
                             diag::note_asm_missing_constraint_modifier)
                  << SuggestedModifier;
-        SuggestedModifier = "%" + SuggestedModifier + Piece.getString();
-        B << FixItHint::CreateReplacement(Piece.getRange(), SuggestedModifier);
+        if(isa<StringLiteral>(Constraint)) {
+          SuggestedModifier = "%" + SuggestedModifier + Piece.getString();
+          B << FixItHint::CreateReplacement(Piece.getRange(), SuggestedModifier);
+        }
       }
     }
   }
@@ -708,7 +741,7 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
 
   // Check for conflicts between clobber list and input or output lists
   SourceLocation ConstraintLoc =
-      getClobberConflictLocation(Exprs, Constraints, Clobbers, NumClobbers,
+      getClobberConflictLocation(Exprs, constraints.data(), clobbers.data(), NumClobbers,
                                  NumLabels,
                                  Context.getTargetInfo(), Context);
   if (ConstraintLoc.isValid())
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index a09f623ff8fbf..06d41a8154ca3 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -8552,25 +8552,39 @@ template<typename Derived>
 StmtResult
 TreeTransform<Derived>::TransformGCCAsmStmt(GCCAsmStmt *S) {
 
+
   SmallVector<Expr*, 8> Constraints;
   SmallVector<Expr*, 8> Exprs;
   SmallVector<IdentifierInfo *, 4> Names;
 
-  ExprResult AsmString;
   SmallVector<Expr*, 8> Clobbers;
 
   bool ExprsChanged = false;
 
+  auto RebuildString = [&] (Expr* E) {
+      ExprResult Result = getDerived().TransformExpr(E);
+      if (Result.isInvalid())
+        return Result;
+      if(!Result.isInvalid() && Result.get() != E) {
+          ExprsChanged = true;
+          Result = SemaRef.ActOnGCCAsmStmtString(Result.get(), /*ForLabel=*/false);
+      }
+      return Result;
+  };
+
   // Go through the outputs.
   for (unsigned I = 0, E = S->getNumOutputs(); I != E; ++I) {
     Names.push_back(S->getOutputIdentifier(I));
 
-    // No need to transform the constraint literal.
-    Constraints.push_back(S->getOutputConstraintLiteral(I));
+    ExprResult Result = RebuildString(S->getOutputConstraintExpr(I));
+    if (Result.isInvalid())
+      return StmtError();
+
+    Constraints.push_back(Result.get());
 
     // Transform the output expr.
     Expr *OutputExpr = S->getOutputExpr(I);
-    ExprResult Result = getDerived().TransformExpr(OutputExpr);
+    Result = getDerived().TransformExpr(OutputExpr);
     if (Result.isInvalid())
       return StmtError();
 
@@ -8583,12 +8597,15 @@ TreeTransform<Derived>::TransformGCCAsmStmt(GCCAsmStmt *S) {
   for (unsigned I = 0, E = S->getNumInputs(); I != E; ++I) {
     Names.push_back(S->getInputIdentifier(I));
 
-    // No need to transform the constraint literal.
-    Constraints.push_back(S->getInputConstraintLiteral(I));
+    ExprResult Result = RebuildString(S->getInputConstraintExpr(I));
+    if (Result.isInvalid())
+      return StmtError();
+
+    Constraints.push_back(Result.get());
 
     // Transform the input expr.
     Expr *InputExpr = S->getInputExpr(I);
-    ExprResult Result = getDerived().TransformExpr(InputExpr);
+    Result = getDerived().TransformExpr(InputExpr);
     if (Result.isInvalid())
       return StmtError();
 
@@ -8607,15 +8624,22 @@ TreeTransform<Derived>::TransformGCCAsmStmt(GCCAsmStmt *S) {
     ExprsChanged |= Result.get() != S->getLabelExpr(I);
     Exprs.push_back(Result.get());
   }
-  if (!getDerived().AlwaysRebuild() && !ExprsChanged)
-    return S;
 
   // Go through the clobbers.
-  for (unsigned I = 0, E = S->getNumClobbers(); I != E; ++I)
-    Clobbers.push_back(S->getClobberStringLiteral(I));
+  for (unsigned I = 0, E = S->getNumClobbers(); I != E; ++I) {
+      ExprResult Result = RebuildString(S->getClobberExpr(I));
+      if (Result.isInvalid())
+        return StmtError();
+      Clobbers.push_back(Result.get());
+  }
+
+  ExprResult AsmString = RebuildString(S->getAsmStringExpr());
+  if (AsmString.isInvalid())
+    return StmtError();
+
+  if (!getDerived().AlwaysRebuild() && !ExprsChanged)
+    return S;
 
-  // No need to transform the asm string literal.
-  AsmString = S->getAsmString();
   return getDerived().RebuildGCCAsmStmt(S->getAsmLoc(), S->isSimple(),
                                         S->isVolatile(), S->getNumOutputs(),
                                         S->getNumInputs(), Names.data(),
diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp
index 48f9f89bd6e4c..7ad1216cb53e2 100644
--- a/clang/lib/Serialization/ASTReaderStmt.cpp
+++ b/clang/lib/Serialization/ASTReaderStmt.cpp
@@ -381,7 +381,7 @@ void ASTStmtReader::VisitGCCAsmStmt(GCCAsmStmt *S) {
   VisitAsmStmt(S);
   S->NumLabels = Record.readInt();
   S->setRParenLoc(readSourceLocation());
-  S->setAsmString(cast_or_null<StringLiteral>(Record.readSubStmt()));
+  S->setAsmString(cast_or_null<Expr>(Record.readSubStmt()));
 
   unsigned NumOutputs = S->getNumOutputs();
   unsigned NumInputs = S->getNumInputs();
@@ -390,18 +390,18 @@ void ASTStmtReader::VisitGCCAsmStmt(GCCAsmStmt *S) {
 
   // Outputs and inputs
   SmallVector<IdentifierInfo *, 16> Names;
-  SmallVector<StringLiteral*, 16> Constraints;
+  SmallVector<Expr*, 16> Constraints;
   SmallVector<Stmt*, 16> Exprs;
   for (unsigned I = 0, N = NumOutputs + NumInputs; I != N; ++I) {
     Names.push_back(Record.readIdentifier());
-    Constraints.push_back(cast_or_null<StringLiteral>(Record.readSubStmt()));
+    Constraints.push_back(cast_or_null<Expr>(Record.readSubStmt()));
     Exprs.push_back(Record.readSubStmt());
   }
 
   // Constraints
-  SmallVector<StringLiteral*, 16> Clobbers;
+  SmallVector<Expr*, 16> Clobbers;
   for (unsigned I = 0; I != NumClobbers; ++I)
-    Clobbers.push_back(cast_or_null<StringLiteral>(Record.readSubStmt()));
+    Clobbers.push_back(cast_or_null<Expr>(Record.readSubStmt()));
 
   // Labels
   for (unsigned I = 0, N = NumLabels; I != N; ++I) {
diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp
index aa5a7854394a0..32211ced4ff15 100644
--- a/clang/lib/Serialization/ASTWriterStmt.cpp
+++ b/clang/lib/Serialization/ASTWriterStmt.cpp
@@ -361,25 +361,25 @@ void ASTStmtWriter::VisitGCCAsmStmt(GCCAsmStmt *S) {
   VisitAsmStmt(S);
   Record.push_back(S->getNumLabels());
   Record.AddSourceLocation(S->getRParenLoc());
-  Record.AddStmt(S->getAsmString());
+  Record.AddStmt(S->getAsmStringExpr());
 
   // Outputs
   for (unsigned I = 0, N = S->getNumOutputs(); I != N; ++I) {
     Record.AddIdentifierRef(S->getOutputIdentifier(I));
-    Record.AddStmt(S->getOutputConstraintLiteral(I));
+    Record.AddStmt(S->getOutputConstraintExpr(I));
     Record.AddStmt(S->getOutputExpr(I));
   }
 
   // Inputs
   for (unsigned I = 0, N = S->getNumInputs(); I != N; ++I) {
     Record.AddIdentifierRef(S->getInputIdentifier(I));
-    Record.AddStmt(S->getInputConstraintLiteral(I));
+    Record.AddStmt(S->getInputConstraintExpr(I));
     Record.AddStmt(S->getInputExpr(I));
   }
 
   // Clobbers
   for (unsigned I = 0, N = S->getNumClobbers(); I != N; ++I)
-    Record.AddStmt(S->getClobberStringLiteral(I));
+    Record.AddStmt(S->getClobberExpr(I));
 
   // Labels
   for (unsigned I = 0, N = S->getNumLabels(); I != N; ++I) {

>From 5221a3ff4e66a3e26c84de5904f8be23202432df Mon Sep 17 00:00:00 2001
From: Corentin Jabot <corentinjabot at gmail.com>
Date: Wed, 12 Mar 2025 19:42:22 +0100
Subject: [PATCH 2/2] format

---
 clang/lib/Parse/Parser.cpp | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp
index baf264c808820..de2fb168405df 100644
--- a/clang/lib/Parse/Parser.cpp
+++ b/clang/lib/Parse/Parser.cpp
@@ -1688,6 +1688,9 @@ ExprResult Parser::ParseAsmStringLiteral(bool ForAsmLabel) {
     SourceLocation   RParenLoc;
     ParsedType CastTy;
 
+    Sema::ExpressionEvaluationContext Context =
+        Sema::ExpressionEvaluationContext::ConstantEvaluated;
+
     AsmString = ParseParenExpression(ExprType, true/*stopIfCastExpr*/,
                                    false, CastTy, RParenLoc);
     if(!AsmString.isUsable())



More information about the cfe-commits mailing list