summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang/lib/Sema/SemaAttr.cpp11
-rw-r--r--clang/lib/Sema/SemaDeclAttr.cpp16
-rw-r--r--clang/lib/Sema/SemaInit.cpp4
-rw-r--r--clang/lib/Sema/SemaTemplateInstantiateDecl.cpp15
-rw-r--r--clang/test/SemaCXX/attr-gsl-owner-pointer-std.cpp53
-rw-r--r--clang/test/SemaCXX/attr-gsl-owner-pointer.cpp17
-rw-r--r--clang/unittests/Sema/CMakeLists.txt2
-rw-r--r--clang/unittests/Sema/GslOwnerPointerInference.cpp61
8 files changed, 164 insertions, 15 deletions
diff --git a/clang/lib/Sema/SemaAttr.cpp b/clang/lib/Sema/SemaAttr.cpp
index e2542edf6ed..23cb47481f3 100644
--- a/clang/lib/Sema/SemaAttr.cpp
+++ b/clang/lib/Sema/SemaAttr.cpp
@@ -88,13 +88,11 @@ void Sema::AddMsStructLayoutForRecord(RecordDecl *RD) {
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 @@ void Sema::inferGslOwnerPointerAttribute(CXXRecordDecl *Record) {
// 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()))
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index 2a72f7d5c61..b694c058a3a 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -4592,9 +4592,11 @@ static void handleLifetimeCategoryAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
}
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 @@ static void handleLifetimeCategoryAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
}
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()));
+ }
}
}
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index 289a1403cd8..ee9963fca77 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -6561,7 +6561,7 @@ static void visitLocalsRetainedByReferenceBinding(IndirectLocalPath &Path,
template <typename T> static bool isRecordWithAttr(QualType Type) {
if (auto *RD = Type->getAsCXXRecordDecl())
- return RD->getCanonicalDecl()->hasAttr<T>();
+ return RD->hasAttr<T>();
return false;
}
@@ -6672,7 +6672,7 @@ static void handleGslAnnotatedTypes(IndirectLocalPath &Path, Expr *Call,
if (auto *CCE = dyn_cast<CXXConstructExpr>(Call)) {
const auto *Ctor = CCE->getConstructor();
- const CXXRecordDecl *RD = Ctor->getParent()->getCanonicalDecl();
+ const CXXRecordDecl *RD = Ctor->getParent();
if (CCE->getNumArgs() > 0 && RD->hasAttr<PointerAttr>())
VisitPointerArg(Ctor->getParamDecl(0), CCE->getArgs()[0]);
}
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 25d0db80398..2e76dc1a584 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -552,6 +552,18 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs,
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 @@ Decl *TemplateDeclInstantiator::InstantiateTypedefNameDecl(TypedefNameDecl *D,
SemaRef.InstantiateAttrs(TemplateArgs, D, Typedef);
+ if (D->getUnderlyingType()->getAs<DependentNameType>())
+ SemaRef.inferGslPointerAttribute(Typedef);
+
Typedef->setAccess(D->getAccess());
return Typedef;
diff --git a/clang/test/SemaCXX/attr-gsl-owner-pointer-std.cpp b/clang/test/SemaCXX/attr-gsl-owner-pointer-std.cpp
index 29675c2ac7e..352e1e47358 100644
--- a/clang/test/SemaCXX/attr-gsl-owner-pointer-std.cpp
+++ b/clang/test/SemaCXX/attr-gsl-owner-pointer-std.cpp
@@ -92,6 +92,59 @@ public:
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>
diff --git a/clang/test/SemaCXX/attr-gsl-owner-pointer.cpp b/clang/test/SemaCXX/attr-gsl-owner-pointer.cpp
index 1c3deb3982e..5b438822ba2 100644
--- a/clang/test/SemaCXX/attr-gsl-owner-pointer.cpp
+++ b/clang/test/SemaCXX/attr-gsl-owner-pointer.cpp
@@ -105,3 +105,20 @@ class [[gsl::Owner(int)]] AddTheSameLater{};
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.
diff --git a/clang/unittests/Sema/CMakeLists.txt b/clang/unittests/Sema/CMakeLists.txt
index 51e8d6c5b43..6832908e7fb 100644
--- a/clang/unittests/Sema/CMakeLists.txt
+++ b/clang/unittests/Sema/CMakeLists.txt
@@ -5,11 +5,13 @@ set(LLVM_LINK_COMPONENTS
add_clang_unittest(SemaTests
ExternalSemaSourceTest.cpp
CodeCompleteTest.cpp
+ GslOwnerPointerInference.cpp
)
clang_target_link_libraries(SemaTests
PRIVATE
clangAST
+ clangASTMatchers
clangBasic
clangFrontend
clangParse
diff --git a/clang/unittests/Sema/GslOwnerPointerInference.cpp b/clang/unittests/Sema/GslOwnerPointerInference.cpp
new file mode 100644
index 00000000000..e340ccb4127
--- /dev/null
+++ b/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
OpenPOWER on IntegriCloud