aaron.ballman created this revision.
aaron.ballman added reviewers: rsmith, haberman.
aaron.ballman requested review of this revision.
Herald added a project: clang.

It is useful statement an attribute is being applied to when performing 
semantic processing of the attribute during template instantiation. This 
functionality is not currently needed by existing attributes, but is 
anticipated to be used by new attributes being worked on.

One design choice with this is whether to transform attributes then the 
attributed statement, or to transform the attributed statement and then the 
attributes. I elected to transform the attributed statement first because it 
seems less likely that the statement transformation would require the 
instanatiated attributes compared to when we transform attributes (those would 
benefit from knowing the fully instantiated statement). This patch passes a 
non-`const Stmt *` to `TransformAttr()` in case the attribute instantiation 
needs to modify the attributed statement for some reason.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D99983

Files:
  clang/lib/Sema/SemaTemplateInstantiate.cpp
  clang/lib/Sema/TreeTransform.h

Index: clang/lib/Sema/TreeTransform.h
===================================================================
--- clang/lib/Sema/TreeTransform.h
+++ clang/lib/Sema/TreeTransform.h
@@ -379,8 +379,14 @@
   /// of attribute. Subclasses may override this function to transform
   /// attributed statements using some other mechanism.
   ///
+  /// The \c TransformedStmt parameter points to the substituted statement and
+  /// is non-const explicitly so that transformations of the attribute that
+  /// need to set state on the statement they apply to can do so if needed.
+  /// Note that \c TransformedStmt will be null when transforming type
+  /// attributes.
+  ///
   /// \returns the transformed attribute
-  const Attr *TransformAttr(const Attr *S);
+  const Attr *TransformAttr(const Attr *A, Stmt *TransformedStmt);
 
 /// Transform the specified attribute.
 ///
@@ -390,7 +396,9 @@
 /// \returns the transformed attribute.
 #define ATTR(X)
 #define PRAGMA_SPELLING_ATTR(X)                                                \
-  const X##Attr *Transform##X##Attr(const X##Attr *R) { return R; }
+  const X##Attr *Transform##X##Attr(const X##Attr *R, Stmt *TransformedStmt) { \
+    return R;                                                                  \
+  }
 #include "clang/Basic/AttrList.inc"
 
   /// Transform the given expression.
@@ -6734,7 +6742,8 @@
 
   // oldAttr can be null if we started with a QualType rather than a TypeLoc.
   const Attr *oldAttr = TL.getAttr();
-  const Attr *newAttr = oldAttr ? getDerived().TransformAttr(oldAttr) : nullptr;
+  const Attr *newAttr =
+      oldAttr ? getDerived().TransformAttr(oldAttr, nullptr) : nullptr;
   if (oldAttr && !newAttr)
     return QualType();
 
@@ -7287,19 +7296,20 @@
 }
 
 template <typename Derived>
-const Attr *TreeTransform<Derived>::TransformAttr(const Attr *R) {
-  if (!R)
-    return R;
+const Attr *TreeTransform<Derived>::TransformAttr(const Attr *A,
+                                                  Stmt *TransformedStmt) {
+  if (!A)
+    return A;
 
-  switch (R->getKind()) {
+  switch (A->getKind()) {
 // Transform attributes with a pragma spelling by calling TransformXXXAttr.
 #define ATTR(X)
 #define PRAGMA_SPELLING_ATTR(X)                                                \
   case attr::X:                                                                \
-    return getDerived().Transform##X##Attr(cast<X##Attr>(R));
+    return getDerived().Transform##X##Attr(cast<X##Attr>(A), TransformedStmt);
 #include "clang/Basic/AttrList.inc"
   default:
-    return R;
+    return A;
   }
 }
 
@@ -7307,20 +7317,26 @@
 StmtResult
 TreeTransform<Derived>::TransformAttributedStmt(AttributedStmt *S,
                                                 StmtDiscardKind SDK) {
+  // Transform the attributed statement first so that we can pass the
+  // transformed version in to the attribute handler. This is necessary because
+  // attributes that need to perform semantic checking are more likely to need
+  // the transformed statement than statement semantic checking is likely to
+  // need the transformed attributes. In such a case, the TransformFooAttr()
+  // function can mutate the non-const transformed statement that it is passed.
+  StmtResult SubStmt = getDerived().TransformStmt(S->getSubStmt(), SDK);
+  if (SubStmt.isInvalid())
+    return StmtError();
+
   bool AttrsChanged = false;
   SmallVector<const Attr *, 1> Attrs;
 
   // Visit attributes and keep track if any are transformed.
   for (const auto *I : S->getAttrs()) {
-    const Attr *R = getDerived().TransformAttr(I);
+    const Attr *R = getDerived().TransformAttr(I, SubStmt.get());
     AttrsChanged |= (I != R);
     Attrs.push_back(R);
   }
 
-  StmtResult SubStmt = getDerived().TransformStmt(S->getSubStmt(), SDK);
-  if (SubStmt.isInvalid())
-    return StmtError();
-
   if (SubStmt.get() == S->getSubStmt() && !AttrsChanged)
     return S;
 
Index: clang/lib/Sema/SemaTemplateInstantiate.cpp
===================================================================
--- clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -1074,7 +1074,8 @@
                           NamedDecl *FirstQualifierInScope = nullptr,
                           bool AllowInjectedClassName = false);
 
-    const LoopHintAttr *TransformLoopHintAttr(const LoopHintAttr *LH);
+    const LoopHintAttr *TransformLoopHintAttr(const LoopHintAttr *LH,
+                                              Stmt *TransformedStmt);
 
     ExprResult TransformPredefinedExpr(PredefinedExpr *E);
     ExprResult TransformDeclRefExpr(DeclRefExpr *E);
@@ -1485,7 +1486,7 @@
 }
 
 const LoopHintAttr *
-TemplateInstantiator::TransformLoopHintAttr(const LoopHintAttr *LH) {
+TemplateInstantiator::TransformLoopHintAttr(const LoopHintAttr *LH, Stmt *) {
   Expr *TransformedExpr = getDerived().TransformExpr(LH->getValue()).get();
 
   if (TransformedExpr == LH->getValue())
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to