llvmbot wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: None (awson)

<details>
<summary>Changes</summary>

This is a rework of https://github.com/llvm/llvm-project/pull/156846.

We now only clone (parenthesized) string literals only when doing 
`TreeTransform::TransformExpr`.

Non-dependent case remains unaffected thus.

---
Full diff: https://github.com/llvm/llvm-project/pull/172995.diff


4 Files Affected:

- (modified) clang/include/clang/AST/Expr.h (+4) 
- (modified) clang/lib/AST/Expr.cpp (+79) 
- (modified) clang/lib/Sema/TreeTransform.h (+1) 
- (added) clang/test/SemaCXX/GH112189.cpp (+41) 


``````````diff
diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h
index 3e30a8b420f19..4e219d50111fe 100644
--- a/clang/include/clang/AST/Expr.h
+++ b/clang/include/clang/AST/Expr.h
@@ -1023,6 +1023,10 @@ class Expr : public ValueStmt {
     return skipRValueSubobjectAdjustments(CommaLHSs, Adjustments);
   }
 
+  /// If the expression is a (possibly parenthesized) string literal
+  /// then make a copy of it.
+  Expr *CloneIfIAmAStringLiteral(ASTContext &Ctx);
+
   /// Checks that the two Expr's will refer to the same value as a comparison
   /// operand.  The caller must ensure that the values referenced by the Expr's
   /// are not modified between E1 and E2 or the result my be invalid.
diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp
index 616db5df23c5f..ed7cfa8de83b4 100644
--- a/clang/lib/AST/Expr.cpp
+++ b/clang/lib/AST/Expr.cpp
@@ -133,6 +133,85 @@ const Expr *Expr::skipRValueSubobjectAdjustments(
   return E;
 }
 
+static StringLiteral *CloneStringLiteral(const StringLiteral *SL,
+                                         ASTContext &C) {
+  SourceLocation *SLocs = new (C) SourceLocation[SL->getNumConcatenated()];
+  std::copy(SL->tokloc_begin(), SL->tokloc_end(), SLocs);
+  return StringLiteral::Create(
+      C, SL->getBytes(), SL->getKind(), SL->isPascal(), SL->getType(),
+      ArrayRef<SourceLocation>(SLocs, SL->getNumConcatenated()));
+}
+
+// Exactly follow `IgnoreParensSingleStep` (`AST/IgnoreExpr.h`)
+// We only recursively visit those subexpressions which 
`IgnoreParensSingleStep`
+// drills down to.
+Expr *Expr::CloneIfIAmAStringLiteral(ASTContext &C){
+  if (auto *SL = dyn_cast<StringLiteral>(this)) {
+    return CloneStringLiteral(SL, C);
+  }
+
+  if (auto *PE = dyn_cast<ParenExpr>(this)) {
+    return new (C)
+        ParenExpr(PE->getBeginLoc(), PE->getEndLoc(),
+                  PE->getSubExpr()->CloneIfIAmAStringLiteral(C));
+  }
+
+  if (auto *UO = dyn_cast<UnaryOperator>(this)) {
+    if (UO->getOpcode() == UO_Extension) {
+      return UnaryOperator::Create(
+          C, UO->getSubExpr()->CloneIfIAmAStringLiteral(C), UO_Extension,
+          UO->getType(), UO->getValueKind(), UO->getObjectKind(),
+          UO->getBeginLoc(), UO->canOverflow(), UO->getFPOptionsOverride());
+    }
+  }
+
+  else if (auto *GSE = dyn_cast<GenericSelectionExpr>(this)) {
+    if (!GSE->isResultDependent()) {
+      ArrayRef<Expr *> GSEAEs = GSE->getAssocExprs();
+      Expr **NewGSEAEs = new (C) Expr *[GSEAEs.size()];
+      std::copy(GSEAEs.begin(), GSEAEs.end(), NewGSEAEs);
+      NewGSEAEs[GSE->getResultIndex()] =
+          GSE->getResultExpr()->CloneIfIAmAStringLiteral(C);
+
+      auto GSECreate = [&](auto *ExprOrTSI) -> Expr * {
+        return GenericSelectionExpr::Create(
+            C, GSE->getGenericLoc(), ExprOrTSI, GSE->getAssocTypeSourceInfos(),
+            ArrayRef<Expr *>(NewGSEAEs, GSEAEs.size()), GSE->getDefaultLoc(),
+            GSE->getRParenLoc(), GSE->containsUnexpandedParameterPack(),
+            GSE->getResultIndex());
+      };
+
+      return GSE->isExprPredicate() ? GSECreate(GSE->getControllingExpr())
+                                    : GSECreate(GSE->getControllingType());
+    }
+  }
+
+  else if (auto *CE = dyn_cast<ChooseExpr>(this)) {
+    if (!CE->isConditionDependent()) {
+      // Drills to `CE->getChosenSubExpr()`
+      const bool isCondTrue = CE->isConditionTrue();
+      return new (C) ChooseExpr(
+          CE->getBeginLoc(), CE->getCond(),
+          isCondTrue ? CE->getLHS()->CloneIfIAmAStringLiteral(C)
+                     : CE->getLHS(),
+          isCondTrue ? CE->getRHS()
+                     : CE->getRHS()->CloneIfIAmAStringLiteral(C),
+          CE->getType(), CE->getValueKind(), CE->getObjectKind(),
+          CE->getRParenLoc(), CE->isConditionTrue());
+    }
+  }
+
+  else if (auto *PE = dyn_cast<PredefinedExpr>(this)) {
+    if (PE->isTransparent() && PE->getFunctionName()) {
+      return PredefinedExpr::Create(
+          C, PE->getLocation(), PE->getType(), PE->getIdentKind(),
+          PE->isTransparent(), CloneStringLiteral(PE->getFunctionName(), C));
+    }
+  }
+
+  return this;
+}
+
 bool Expr::isKnownToHaveBooleanValue(bool Semantic) const {
   const Expr *E = IgnoreParens();
 
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index bc923c80b7132..81048c9fe1640 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -4417,6 +4417,7 @@ ExprResult TreeTransform<Derived>::TransformExpr(Expr *E) 
{
   if (!E)
     return E;
 
+  E = E->CloneIfIAmAStringLiteral(getSema().getASTContext());
   switch (E->getStmtClass()) {
     case Stmt::NoStmtClass: break;
 #define STMT(Node, Parent) case Stmt::Node##Class: break;
diff --git a/clang/test/SemaCXX/GH112189.cpp b/clang/test/SemaCXX/GH112189.cpp
new file mode 100644
index 0000000000000..036fd8ea83c0e
--- /dev/null
+++ b/clang/test/SemaCXX/GH112189.cpp
@@ -0,0 +1,41 @@
+// RUN: %clang_cc1 -verify %s
+// expected-no-diagnostics
+
+template<unsigned int SPACE>
+char foo_choose() {
+  char buffer[SPACE] {__builtin_choose_expr(6, "foo", "boo")};
+  return buffer[0];
+}
+
+int boro_choose()
+{
+  int r = foo_choose<10>();
+  r += foo_choose<100>();
+  return r + foo_choose<4>();
+}
+
+template<unsigned int SPACE>
+char foo_gen_ext() {
+  char buffer[SPACE] {__extension__ (_Generic(0, int: (__extension__ "foo" 
)))};
+  return buffer[0];
+}
+
+int boro_gen_ext()
+{
+  int r = foo_gen_ext<10>();
+  r += foo_gen_ext<100>();
+  return r + foo_gen_ext<4>();
+}
+
+template<unsigned int SPACE>
+char foo_paren_predef() {
+  char buffer[SPACE] {(((__FILE__)))};
+  return buffer[0];
+}
+
+int boro_paren_predef()
+{
+  int r = foo_paren_predef<200000>();
+  r += foo_paren_predef<300000>();
+  return r + foo_paren_predef<100000>();
+}

``````````

</details>


https://github.com/llvm/llvm-project/pull/172995
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to