[clang] 652ae4e - [Clang][Sema] Warn when 'exclude_from_explicit_instantiation' attribute is used on local classes and members thereof (#88777)

via cfe-commits cfe-commits at lists.llvm.org
Thu Apr 18 04:48:15 PDT 2024


Author: Krystian Stasiowski
Date: 2024-04-18T07:48:10-04:00
New Revision: 652ae4ecadaa972d70ef5cea3b68f2ff103c4af2

URL: https://github.com/llvm/llvm-project/commit/652ae4ecadaa972d70ef5cea3b68f2ff103c4af2
DIFF: https://github.com/llvm/llvm-project/commit/652ae4ecadaa972d70ef5cea3b68f2ff103c4af2.diff

LOG: [Clang][Sema] Warn when 'exclude_from_explicit_instantiation' attribute is used on local classes and members thereof (#88777)

A local class and its members declared in a function template are
instantiated alongside the definition of that template. It therefore
does not make sense to apply the `exclude_from_explicit_instantiation`
attribute to such declarations, and this patch adds a warning to
diagnose these cases (in addition to ignoring the attribute).

(The motivation for this patch is to fix a failing test in libc++ for
#84050. In particular, line 199 in `include/__memory/uses_allocator_construction.h`
in libc++ contains the expression `this->__value_` (reduced to 
https://godbolt.org/z/KqEerKWPd) which will be looked up prior
to instantiation once #84050 lands (the lookup context is the 
current instantiation). `_LIBCPP_HIDE_FROM_ABI` includes 
`__attribute__((exclude_from_explicit_instantiation))`, which in the 
reduced example results in `Local` being instantiated with 
`Local::operator A` as its `DeclContext`)

Added: 
    clang/test/SemaCXX/attr-exclude_from_explicit_instantiation.local-class.cpp

Modified: 
    clang/docs/ReleaseNotes.rst
    clang/include/clang/Basic/DiagnosticSemaKinds.td
    clang/lib/Sema/SemaDeclAttr.cpp

Removed: 
    


################################################################################
diff  --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 6c51c2d1f483ce..3fe15934323c53 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -287,6 +287,9 @@ Attribute Changes in Clang
   This allows the ``_Nullable`` and ``_Nonnull`` family of type attributes to
   apply to this class.
 
+- Clang now warns that the ``exclude_from_explicit_instantiation`` attribute
+  is ignored when applied to a local class or a member thereof.
+
 Improvements to Clang's diagnostics
 -----------------------------------
 - Clang now applies syntax highlighting to the code snippets it

diff  --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 30a8543489f48e..a9f4143c6b375e 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -3669,6 +3669,9 @@ def warn_attribute_dllexport_explicit_instantiation_decl : Warning<
 def warn_attribute_dllexport_explicit_instantiation_def : Warning<
   "'dllexport' attribute ignored on explicit instantiation definition">,
   InGroup<IgnoredAttributes>;
+def warn_attribute_exclude_from_explicit_instantiation_local_class : Warning<
+  "%0 attribute ignored on local class%select{| member}1">,
+  InGroup<IgnoredAttributes>;
 def warn_invalid_initializer_from_system_header : Warning<
   "invalid constructor from class in system header, should not be explicit">,
   InGroup<DiagGroup<"invalid-initializer-from-system-header">>;

diff  --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index c3bf18a3f79e23..363ae93cb62df1 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -984,6 +984,21 @@ static void handleErrorAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
     D->addAttr(EA);
 }
 
+static void handleExcludeFromExplicitInstantiationAttr(Sema &S, Decl *D,
+                                                       const ParsedAttr &AL) {
+  const auto *PD = isa<CXXRecordDecl>(D)
+                       ? cast<DeclContext>(D)
+                       : D->getDeclContext()->getRedeclContext();
+  if (const auto *RD = dyn_cast<CXXRecordDecl>(PD); RD && RD->isLocalClass()) {
+    S.Diag(AL.getLoc(),
+           diag::warn_attribute_exclude_from_explicit_instantiation_local_class)
+        << AL << /*IsMember=*/!isa<CXXRecordDecl>(D);
+    return;
+  }
+  D->addAttr(::new (S.Context)
+                 ExcludeFromExplicitInstantiationAttr(S.Context, AL));
+}
+
 namespace {
 /// Determines if a given Expr references any of the given function's
 /// ParmVarDecls, or the function's implicit `this` parameter (if applicable).
@@ -9339,6 +9354,9 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
   case ParsedAttr::AT_Error:
     handleErrorAttr(S, D, AL);
     break;
+  case ParsedAttr::AT_ExcludeFromExplicitInstantiation:
+    handleExcludeFromExplicitInstantiationAttr(S, D, AL);
+    break;
   case ParsedAttr::AT_DiagnoseIf:
     handleDiagnoseIfAttr(S, D, AL);
     break;

diff  --git a/clang/test/SemaCXX/attr-exclude_from_explicit_instantiation.local-class.cpp b/clang/test/SemaCXX/attr-exclude_from_explicit_instantiation.local-class.cpp
new file mode 100644
index 00000000000000..f0b2cec095c97f
--- /dev/null
+++ b/clang/test/SemaCXX/attr-exclude_from_explicit_instantiation.local-class.cpp
@@ -0,0 +1,64 @@
+// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify %s
+
+// Test that the exclude_from_explicit_instantiation attribute is ignored
+// for local classes and members thereof.
+
+#define EXCLUDE_FROM_EXPLICIT_INSTANTIATION __attribute__((exclude_from_explicit_instantiation)) // expected-note 0+{{expanded from macro}}
+
+namespace N0 {
+
+  template<typename T>
+  void f() {
+    struct EXCLUDE_FROM_EXPLICIT_INSTANTIATION A { // expected-warning {{attribute ignored on local class}}
+                                                   // expected-note at -1 2{{in instantiation of}}
+      EXCLUDE_FROM_EXPLICIT_INSTANTIATION void g(T t) { // expected-warning {{attribute ignored on local class member}}
+        *t; // expected-error {{indirection requires pointer operand ('int' invalid)}}
+      }
+
+      struct EXCLUDE_FROM_EXPLICIT_INSTANTIATION B { // expected-warning {{attribute ignored on local class}}
+        void h(T t) {
+          *t; // expected-error {{indirection requires pointer operand ('int' invalid)}}
+        }
+      };
+    };
+  }
+
+  template void f<int>(); // expected-note 2{{in instantiation of}}
+
+}
+
+// This is a reduced example from libc++ which required that 'value'
+// be prefixed with 'this->' because the definition of 'Local::operator A'
+// was not instantiated when the definition of 'g' was.
+namespace N1 {
+
+  struct A { };
+
+  struct B {
+    operator A() {
+      return A();
+    }
+  };
+
+  template<typename T>
+  auto f(T t) {
+    return A(t);
+  }
+
+  template<typename T>
+  auto g(T t) {
+    struct Local {
+      T value;
+
+      EXCLUDE_FROM_EXPLICIT_INSTANTIATION // expected-warning {{attribute ignored on local class member}}
+      operator A() {
+        return A(value);
+      }
+    };
+
+    return f(Local(t));
+  }
+
+  auto x = g(B());
+
+}


        


More information about the cfe-commits mailing list