mgehre updated this revision to Diff 216247.
mgehre marked 6 inline comments as done.
mgehre added a comment.
Herald added a subscriber: mgorny.

- Put OwnerAttr/PointerAttr on all redeclarations
- clang/lib/Sema/SemaAttr.cpp: Use Attribute::CreateImplicit as requested in 
review


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D66179/new/

https://reviews.llvm.org/D66179

Files:
  clang/lib/Sema/SemaAttr.cpp
  clang/lib/Sema/SemaDeclAttr.cpp
  clang/lib/Sema/SemaInit.cpp
  clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
  clang/test/SemaCXX/attr-gsl-owner-pointer-std.cpp
  clang/test/SemaCXX/attr-gsl-owner-pointer.cpp
  clang/unittests/Sema/CMakeLists.txt
  clang/unittests/Sema/GslOwnerPointerInference.cpp

Index: clang/unittests/Sema/GslOwnerPointerInference.cpp
===================================================================
--- /dev/null
+++ clang/unittests/Sema/GslOwnerPointerInference.cpp
@@ -0,0 +1,61 @@
+//== unittests/Sema/GslOwnerPointerInference.cpp - gsl::Owner/Pointer ========//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "../ASTMatchers/ASTMatchersTest.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "gtest/gtest.h"
+
+namespace clang {
+using namespace ast_matchers;
+
+TEST(OwnerPointer, BothHaveAttributes) {
+  EXPECT_TRUE(matches(
+    R"cpp(
+      template<class T>
+      class [[gsl::Owner]] C;
+
+      template<class T>
+      class [[gsl::Owner]] C {};
+
+      C<int> c;
+  )cpp",
+    classTemplateSpecializationDecl(hasName("C"), hasAttr(clang::attr::Owner))));
+}
+
+TEST(OwnerPointer, ForwardDeclOnly) {
+  EXPECT_TRUE(matches(
+    R"cpp(
+      template<class T>
+      class [[gsl::Owner]] C;
+
+      template<class T>
+      class C {};
+
+      C<int> c;
+  )cpp",
+    classTemplateSpecializationDecl(hasName("C"), hasAttr(clang::attr::Owner))));
+}
+
+TEST(OwnerPointer, LateForwardDeclOnly) {
+  EXPECT_TRUE(matches(
+    R"cpp(
+      template<class T>
+      class C;
+
+      template<class T>
+      class C {};
+
+      template<class T>
+      class [[gsl::Owner]] C;
+
+      C<int> c;
+  )cpp",
+    classTemplateSpecializationDecl(hasName("C"), hasAttr(clang::attr::Owner))));
+}
+
+} // namespace clang
Index: clang/unittests/Sema/CMakeLists.txt
===================================================================
--- clang/unittests/Sema/CMakeLists.txt
+++ clang/unittests/Sema/CMakeLists.txt
@@ -5,11 +5,13 @@
 add_clang_unittest(SemaTests
   ExternalSemaSourceTest.cpp
   CodeCompleteTest.cpp
+  GslOwnerPointerInference.cpp
   )
 
 clang_target_link_libraries(SemaTests
   PRIVATE
   clangAST
+  clangASTMatchers
   clangBasic
   clangFrontend
   clangParse
Index: clang/test/SemaCXX/attr-gsl-owner-pointer.cpp
===================================================================
--- clang/test/SemaCXX/attr-gsl-owner-pointer.cpp
+++ clang/test/SemaCXX/attr-gsl-owner-pointer.cpp
@@ -105,3 +105,20 @@
 class [[gsl::Owner(int)]] AddTheSameLater;
 // CHECK: CXXRecordDecl {{.*}} prev {{.*}} AddTheSameLater
 // CHECK: OwnerAttr {{.*}} int
+
+template <class T>
+class [[gsl::Owner]] ForwardDeclared;
+// CHECK: ClassTemplateDecl {{.*}} ForwardDeclared
+// CHECK: OwnerAttr {{.*}}
+// CHECK: ClassTemplateSpecializationDecl {{.*}} ForwardDeclared
+// CHECK: TemplateArgument type 'int'
+// CHECK: OwnerAttr {{.*}}
+
+template <class T>
+class [[gsl::Owner]] ForwardDeclared {
+// CHECK: ClassTemplateDecl {{.*}} ForwardDeclared
+// CHECK: CXXRecordDecl {{.*}} ForwardDeclared definition
+// CHECK: OwnerAttr {{.*}}
+};
+
+static_assert(sizeof(ForwardDeclared<int>), ""); // Force instantiation.
Index: clang/test/SemaCXX/attr-gsl-owner-pointer-std.cpp
===================================================================
--- clang/test/SemaCXX/attr-gsl-owner-pointer-std.cpp
+++ clang/test/SemaCXX/attr-gsl-owner-pointer-std.cpp
@@ -92,6 +92,59 @@
 static_assert(sizeof(unordered_map<int>::iterator), ""); // Force instantiation.
 } // namespace inlinens
 
+// The iterator typedef is a DependentNameType.
+template <typename T>
+class __unordered_multimap_iterator {};
+// CHECK: ClassTemplateDecl {{.*}} __unordered_multimap_iterator
+// CHECK: ClassTemplateSpecializationDecl {{.*}} __unordered_multimap_iterator
+// CHECK: TemplateArgument type 'int'
+// CHECK: PointerAttr
+
+template <typename T>
+class __unordered_multimap_base {
+public:
+  using iterator = __unordered_multimap_iterator<T>;
+};
+
+template <typename T>
+class unordered_multimap {
+  // CHECK: ClassTemplateDecl {{.*}} unordered_multimap
+  // CHECK: OwnerAttr {{.*}}
+  // CHECK: ClassTemplateSpecializationDecl {{.*}} unordered_multimap
+  // CHECK: OwnerAttr {{.*}}
+public:
+  using _Mybase = __unordered_multimap_base<T>;
+  using iterator = typename _Mybase::iterator;
+};
+static_assert(sizeof(unordered_multimap<int>::iterator), ""); // Force instantiation.
+
+// The canonical declaration of the iterator template is not its definition.
+template <typename T>
+class __unordered_multiset_iterator;
+// CHECK: ClassTemplateDecl {{.*}} __unordered_multiset_iterator
+// CHECK: PointerAttr
+// CHECK: ClassTemplateSpecializationDecl {{.*}} __unordered_multiset_iterator
+// CHECK: TemplateArgument type 'int'
+// CHECK: PointerAttr
+
+template <typename T>
+class __unordered_multiset_iterator {
+  // CHECK: ClassTemplateDecl {{.*}} prev {{.*}} __unordered_multiset_iterator
+  // CHECK: PointerAttr
+};
+
+template <typename T>
+class unordered_multiset {
+  // CHECK: ClassTemplateDecl {{.*}} unordered_multiset
+  // CHECK: OwnerAttr {{.*}}
+  // CHECK: ClassTemplateSpecializationDecl {{.*}} unordered_multiset
+  // CHECK: OwnerAttr {{.*}}
+public:
+  using iterator = __unordered_multiset_iterator<T>;
+};
+
+static_assert(sizeof(unordered_multiset<int>::iterator), ""); // Force instantiation.
+
 // std::list has an implicit gsl::Owner attribute,
 // but explicit attributes take precedence.
 template <typename T>
Index: clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
===================================================================
--- clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -552,6 +552,18 @@
       continue;
     }
 
+    if (auto *A = dyn_cast<PointerAttr>(TmplAttr)) {
+      if (!New->hasAttr<PointerAttr>())
+        New->addAttr(A->clone(Context));
+      continue;
+    }
+
+    if (auto *A = dyn_cast<OwnerAttr>(TmplAttr)) {
+      if (!New->hasAttr<OwnerAttr>())
+        New->addAttr(A->clone(Context));
+      continue;
+    }
+
     assert(!TmplAttr->isPackExpansion());
     if (TmplAttr->isLateParsed() && LateAttrs) {
       // Late parsed attributes must be instantiated and attached after the
@@ -711,6 +723,9 @@
 
   SemaRef.InstantiateAttrs(TemplateArgs, D, Typedef);
 
+  if (D->getUnderlyingType()->getAs<DependentNameType>())
+    SemaRef.inferGslPointerAttribute(Typedef);
+
   Typedef->setAccess(D->getAccess());
 
   return Typedef;
Index: clang/lib/Sema/SemaInit.cpp
===================================================================
--- clang/lib/Sema/SemaInit.cpp
+++ clang/lib/Sema/SemaInit.cpp
@@ -6560,7 +6560,7 @@
 
 template <typename T> static bool isRecordWithAttr(QualType Type) {
   if (auto *RD = Type->getAsCXXRecordDecl())
-    return RD->getCanonicalDecl()->hasAttr<T>();
+    return RD->hasAttr<T>();
   return false;
 }
 
Index: clang/lib/Sema/SemaDeclAttr.cpp
===================================================================
--- clang/lib/Sema/SemaDeclAttr.cpp
+++ clang/lib/Sema/SemaDeclAttr.cpp
@@ -4592,9 +4592,11 @@
       }
       return;
     }
-    D->addAttr(::new (S.Context)
-                   OwnerAttr(AL.getRange(), S.Context, DerefTypeLoc,
-                             AL.getAttributeSpellingListIndex()));
+    for (Decl *Redecl : D->redecls()) {
+      Redecl->addAttr(::new (S.Context)
+                          OwnerAttr(AL.getRange(), S.Context, DerefTypeLoc,
+                                    AL.getAttributeSpellingListIndex()));
+    }
   } else {
     if (checkAttrMutualExclusion<OwnerAttr>(S, D, AL))
       return;
@@ -4609,9 +4611,11 @@
       }
       return;
     }
-    D->addAttr(::new (S.Context)
-                   PointerAttr(AL.getRange(), S.Context, DerefTypeLoc,
-                               AL.getAttributeSpellingListIndex()));
+    for (Decl *Redecl : D->redecls()) {
+      Redecl->addAttr(::new (S.Context)
+                          PointerAttr(AL.getRange(), S.Context, DerefTypeLoc,
+                                      AL.getAttributeSpellingListIndex()));
+    }
   }
 }
 
Index: clang/lib/Sema/SemaAttr.cpp
===================================================================
--- clang/lib/Sema/SemaAttr.cpp
+++ clang/lib/Sema/SemaAttr.cpp
@@ -88,13 +88,11 @@
 template <typename Attribute>
 static void addGslOwnerPointerAttributeIfNotExisting(ASTContext &Context,
                                                      CXXRecordDecl *Record) {
-  CXXRecordDecl *Canonical = Record->getCanonicalDecl();
-  if (Canonical->hasAttr<OwnerAttr>() || Canonical->hasAttr<PointerAttr>())
+  if (Record->hasAttr<OwnerAttr>() || Record->hasAttr<PointerAttr>())
     return;
 
-  Canonical->addAttr(::new (Context) Attribute(SourceRange{}, Context,
-                                               /*DerefType*/ nullptr,
-                                               /*Spelling=*/0));
+  for (Decl *Redecl : Record->redecls())
+    Redecl->addAttr(Attribute::CreateImplicit(Context, /*DerefType=*/nullptr));
 }
 
 void Sema::inferGslPointerAttribute(NamedDecl *ND,
@@ -189,8 +187,7 @@
 
   // Handle classes that directly appear in std namespace.
   if (Record->isInStdNamespace()) {
-    CXXRecordDecl *Canonical = Record->getCanonicalDecl();
-    if (Canonical->hasAttr<OwnerAttr>() || Canonical->hasAttr<PointerAttr>())
+    if (Record->hasAttr<OwnerAttr>() || Record->hasAttr<PointerAttr>())
       return;
 
     if (StdOwners.count(Record->getName()))
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to