[clang] [clang] Check specialization for annotation (PR #117315)
Utkarsh Saxena via cfe-commits
cfe-commits at lists.llvm.org
Thu Nov 28 02:47:02 PST 2024
https://github.com/usx95 updated https://github.com/llvm/llvm-project/pull/117315
>From e30ae8a6e0c1df8e33c2add6502342cb269c1cfd Mon Sep 17 00:00:00 2001
From: Utkarsh Saxena <usx at google.com>
Date: Fri, 22 Nov 2024 11:02:49 +0000
Subject: [PATCH 1/5] [clang] Check specialization for annotation
---
clang/lib/Sema/CheckExprLifetime.cpp | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/clang/lib/Sema/CheckExprLifetime.cpp b/clang/lib/Sema/CheckExprLifetime.cpp
index 8886e5e307ddf8..64dc4794b6235a 100644
--- a/clang/lib/Sema/CheckExprLifetime.cpp
+++ b/clang/lib/Sema/CheckExprLifetime.cpp
@@ -253,9 +253,12 @@ static void visitLocalsRetainedByReferenceBinding(IndirectLocalPath &Path,
LocalVisitor Visit);
template <typename T> static bool isRecordWithAttr(QualType Type) {
- if (auto *RD = Type->getAsCXXRecordDecl())
- return RD->hasAttr<T>();
- return false;
+ auto *RD = Type->getAsCXXRecordDecl();
+ if (!RD)
+ return false;
+ if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(RD))
+ RD = CTSD->getSpecializedTemplate()->getTemplatedDecl();
+ return RD->hasAttr<T>();
}
// Decl::isInStdNamespace will return false for iterators in some STL
>From db163394b70054694734c269f5fd61ef438eda3b Mon Sep 17 00:00:00 2001
From: Utkarsh Saxena <usx at google.com>
Date: Thu, 28 Nov 2024 09:01:25 +0000
Subject: [PATCH 2/5] move to Sema.h
---
clang/include/clang/Sema/Sema.h | 12 ++++++++
clang/lib/Sema/CheckExprLifetime.cpp | 45 ++++++++++------------------
clang/lib/Sema/SemaAttr.cpp | 5 ++++
3 files changed, 33 insertions(+), 29 deletions(-)
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 6ea6c67447b6f0..9029d54e90f028 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -1760,6 +1760,18 @@ class Sema final : public SemaBase {
/// Add [[gsl::Pointer]] attributes for std:: types.
void inferGslPointerAttribute(TypedefNameDecl *TD);
+ template <typename T> static bool isRecordWithAttr(QualType Type) {
+ auto *RD = Type->getAsCXXRecordDecl();
+ if (!RD)
+ return false;
+ if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(RD))
+ RD = CTSD->getSpecializedTemplate()->getTemplatedDecl();
+ return RD->hasAttr<T>();
+ }
+
+ /// ....
+ static bool isPointerLikeType(QualType Type);
+
LifetimeCaptureByAttr *ParseLifetimeCaptureByAttr(const ParsedAttr &AL,
StringRef ParamName);
// Processes the argument 'X' in [[clang::lifetime_capture_by(X)]]. Since 'X'
diff --git a/clang/lib/Sema/CheckExprLifetime.cpp b/clang/lib/Sema/CheckExprLifetime.cpp
index 64dc4794b6235a..e18651d8e12ab9 100644
--- a/clang/lib/Sema/CheckExprLifetime.cpp
+++ b/clang/lib/Sema/CheckExprLifetime.cpp
@@ -252,15 +252,6 @@ static void visitLocalsRetainedByReferenceBinding(IndirectLocalPath &Path,
Expr *Init, ReferenceKind RK,
LocalVisitor Visit);
-template <typename T> static bool isRecordWithAttr(QualType Type) {
- auto *RD = Type->getAsCXXRecordDecl();
- if (!RD)
- return false;
- if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(RD))
- RD = CTSD->getSpecializedTemplate()->getTemplatedDecl();
- return RD->hasAttr<T>();
-}
-
// Decl::isInStdNamespace will return false for iterators in some STL
// implementations due to them being defined in a namespace outside of the std
// namespace.
@@ -279,11 +270,6 @@ static bool isInStlNamespace(const Decl *D) {
return DC->isStdNamespace();
}
-static bool isPointerLikeType(QualType Type) {
- return isRecordWithAttr<PointerAttr>(Type) || Type->isPointerType() ||
- Type->isNullPtrType();
-}
-
// Returns true if the given Record decl is a form of `GSLOwner<Pointer>`
// type, e.g. std::vector<string_view>, std::optional<string_view>.
static bool isContainerOfPointer(const RecordDecl *Container) {
@@ -293,7 +279,7 @@ static bool isContainerOfPointer(const RecordDecl *Container) {
return false;
const auto &TAs = CTSD->getTemplateArgs();
return TAs.size() > 0 && TAs[0].getKind() == TemplateArgument::Type &&
- isPointerLikeType(TAs[0].getAsType());
+ Sema::isPointerLikeType(TAs[0].getAsType());
}
return false;
}
@@ -306,7 +292,7 @@ static bool isContainerOfOwner(const RecordDecl *Container) {
return false;
const auto &TAs = CTSD->getTemplateArgs();
return TAs.size() > 0 && TAs[0].getKind() == TemplateArgument::Type &&
- isRecordWithAttr<OwnerAttr>(TAs[0].getAsType());
+ Sema::isRecordWithAttr<OwnerAttr>(TAs[0].getAsType());
}
// Returns true if the given Record is `std::initializer_list<pointer>`.
@@ -317,23 +303,24 @@ static bool isStdInitializerListOfPointer(const RecordDecl *RD) {
return isInStlNamespace(RD) && RD->getIdentifier() &&
RD->getName() == "initializer_list" && TAs.size() > 0 &&
TAs[0].getKind() == TemplateArgument::Type &&
- isPointerLikeType(TAs[0].getAsType());
+ Sema::isPointerLikeType(TAs[0].getAsType());
}
return false;
}
static bool shouldTrackImplicitObjectArg(const CXXMethodDecl *Callee) {
if (auto *Conv = dyn_cast_or_null<CXXConversionDecl>(Callee))
- if (isRecordWithAttr<PointerAttr>(Conv->getConversionType()) &&
+ if (Sema::isRecordWithAttr<PointerAttr>(Conv->getConversionType()) &&
Callee->getParent()->hasAttr<OwnerAttr>())
return true;
if (!isInStlNamespace(Callee->getParent()))
return false;
- if (!isRecordWithAttr<PointerAttr>(
+ if (!Sema::isRecordWithAttr<PointerAttr>(
Callee->getFunctionObjectParameterType()) &&
- !isRecordWithAttr<OwnerAttr>(Callee->getFunctionObjectParameterType()))
+ !Sema::isRecordWithAttr<OwnerAttr>(
+ Callee->getFunctionObjectParameterType()))
return false;
- if (isPointerLikeType(Callee->getReturnType())) {
+ if (Sema::isPointerLikeType(Callee->getReturnType())) {
if (!Callee->getIdentifier())
return false;
return llvm::StringSwitch<bool>(Callee->getName())
@@ -366,7 +353,7 @@ static bool shouldTrackFirstArgument(const FunctionDecl *FD) {
if (!RD->hasAttr<PointerAttr>() && !RD->hasAttr<OwnerAttr>())
return false;
if (FD->getReturnType()->isPointerType() ||
- isRecordWithAttr<PointerAttr>(FD->getReturnType())) {
+ Sema::isRecordWithAttr<PointerAttr>(FD->getReturnType())) {
return llvm::StringSwitch<bool>(FD->getName())
.Cases("begin", "rbegin", "cbegin", "crbegin", true)
.Cases("end", "rend", "cend", "crend", true)
@@ -438,7 +425,7 @@ shouldTrackFirstArgumentForConstructor(const CXXConstructExpr *Ctor) {
return true;
// RHS must be an owner.
- if (!isRecordWithAttr<OwnerAttr>(RHSArgType))
+ if (!Sema::isRecordWithAttr<OwnerAttr>(RHSArgType))
return false;
// Bail out if the RHS is Owner<Pointer>.
@@ -565,7 +552,7 @@ static void visitFunctionCallArguments(IndirectLocalPath &Path, Expr *Call,
// Once we initialized a value with a non gsl-owner reference, it can no
// longer dangle.
if (ReturnType->isReferenceType() &&
- !isRecordWithAttr<OwnerAttr>(ReturnType->getPointeeType())) {
+ !Sema::isRecordWithAttr<OwnerAttr>(ReturnType->getPointeeType())) {
for (const IndirectLocalPathEntry &PE : llvm::reverse(Path)) {
if (PE.Kind == IndirectLocalPathEntry::GslReferenceInit ||
PE.Kind == IndirectLocalPathEntry::LifetimeBoundCall)
@@ -1111,7 +1098,7 @@ static bool shouldRunGSLAssignmentAnalysis(const Sema &SemaRef,
bool EnableGSLAssignmentWarnings = !SemaRef.getDiagnostics().isIgnored(
diag::warn_dangling_lifetime_pointer_assignment, SourceLocation());
return (EnableGSLAssignmentWarnings &&
- (isRecordWithAttr<PointerAttr>(Entity.LHS->getType()) ||
+ (Sema::isRecordWithAttr<PointerAttr>(Entity.LHS->getType()) ||
isAssignmentOperatorLifetimeBound(Entity.AssignmentOperator)));
}
@@ -1146,12 +1133,12 @@ checkExprLifetimeImpl(Sema &SemaRef, const InitializedEntity *InitEntity,
// someContainer.add(std::move(localUniquePtr));
// return p;
if (pathContainsInit(Path) ||
- !isRecordWithAttr<OwnerAttr>(L->getType()))
+ !Sema::isRecordWithAttr<OwnerAttr>(L->getType()))
return false;
} else {
IsGslPtrValueFromGslTempOwner =
MTE && !MTE->getExtendingDecl() &&
- isRecordWithAttr<OwnerAttr>(MTE->getType());
+ Sema::isRecordWithAttr<OwnerAttr>(MTE->getType());
// Skipping a chain of initializing gsl::Pointer annotated objects.
// We are looking only for the final source to find out if it was
// a local or temporary owner or the address of a local variable/param.
@@ -1280,7 +1267,7 @@ checkExprLifetimeImpl(Sema &SemaRef, const InitializedEntity *InitEntity,
auto *DRE = dyn_cast<DeclRefExpr>(L);
// Suppress false positives for code like the one below:
// Ctor(unique_ptr<T> up) : pointer(up.get()), owner(move(up)) {}
- if (DRE && isRecordWithAttr<OwnerAttr>(DRE->getType()))
+ if (DRE && Sema::isRecordWithAttr<OwnerAttr>(DRE->getType()))
return false;
auto *VD = DRE ? dyn_cast<VarDecl>(DRE->getDecl()) : nullptr;
@@ -1441,7 +1428,7 @@ checkExprLifetimeImpl(Sema &SemaRef, const InitializedEntity *InitEntity,
break;
}
case LK_LifetimeCapture: {
- if (isPointerLikeType(Init->getType()))
+ if (Sema::isPointerLikeType(Init->getType()))
Path.push_back({IndirectLocalPathEntry::GslPointerInit, Init});
break;
}
diff --git a/clang/lib/Sema/SemaAttr.cpp b/clang/lib/Sema/SemaAttr.cpp
index 9fbad7ed67ccbe..9d21a01cd1b186 100644
--- a/clang/lib/Sema/SemaAttr.cpp
+++ b/clang/lib/Sema/SemaAttr.cpp
@@ -215,6 +215,11 @@ void Sema::inferGslOwnerPointerAttribute(CXXRecordDecl *Record) {
inferGslPointerAttribute(Record, Record);
}
+bool Sema::isPointerLikeType(QualType Type) {
+ return isRecordWithAttr<PointerAttr>(Type) || Type->isPointerType() ||
+ Type->isNullPtrType();
+}
+
void Sema::inferLifetimeBoundAttribute(FunctionDecl *FD) {
if (FD->getNumParams() == 0)
return;
>From 9b412ba242f47f2d16f53615dba6cbd2392a5042 Mon Sep 17 00:00:00 2001
From: Utkarsh Saxena <usx at google.com>
Date: Thu, 28 Nov 2024 09:12:46 +0000
Subject: [PATCH 3/5] reuse in lifetime capture by
---
clang/lib/Sema/SemaAttr.cpp | 14 +-------------
1 file changed, 1 insertion(+), 13 deletions(-)
diff --git a/clang/lib/Sema/SemaAttr.cpp b/clang/lib/Sema/SemaAttr.cpp
index ba87262fc6d435..53a7387ad69353 100644
--- a/clang/lib/Sema/SemaAttr.cpp
+++ b/clang/lib/Sema/SemaAttr.cpp
@@ -274,18 +274,6 @@ void Sema::inferLifetimeBoundAttribute(FunctionDecl *FD) {
}
}
-static bool isPointerLikeType(QualType QT) {
- QT = QT.getNonReferenceType();
- if (QT->isPointerType())
- return true;
- auto *RD = QT->getAsCXXRecordDecl();
- if (!RD)
- return false;
- if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(RD))
- RD = CTSD->getSpecializedTemplate()->getTemplatedDecl();
- return RD->hasAttr<PointerAttr>();
-}
-
void Sema::inferLifetimeCaptureByAttribute(FunctionDecl *FD) {
if (!FD)
return;
@@ -304,7 +292,7 @@ void Sema::inferLifetimeCaptureByAttribute(FunctionDecl *FD) {
if (PVD->hasAttr<LifetimeCaptureByAttr>())
return;
for (ParmVarDecl *PVD : MD->parameters()) {
- if (isPointerLikeType(PVD->getType())) {
+ if (isPointerLikeType(PVD->getType().getNonReferenceType())) {
int CaptureByThis[] = {LifetimeCaptureByAttr::THIS};
PVD->addAttr(
LifetimeCaptureByAttr::CreateImplicit(Context, CaptureByThis, 1));
>From f9f863f14bb8d65cfeaf34afad8c101b96b46eca Mon Sep 17 00:00:00 2001
From: Utkarsh Saxena <usx at google.com>
Date: Thu, 28 Nov 2024 10:45:56 +0000
Subject: [PATCH 4/5] address comments
---
clang/include/clang/Sema/Sema.h | 12 +-------
clang/lib/Sema/CheckExprLifetime.cpp | 43 ++++++++++++++++++++--------
clang/lib/Sema/SemaAttr.cpp | 6 ----
3 files changed, 32 insertions(+), 29 deletions(-)
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index ebf09aa40d592f..c2182ddf7abff6 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -1763,17 +1763,7 @@ class Sema final : public SemaBase {
/// Add [[gsl::Pointer]] attributes for std:: types.
void inferGslPointerAttribute(TypedefNameDecl *TD);
- template <typename T> static bool isRecordWithAttr(QualType Type) {
- auto *RD = Type->getAsCXXRecordDecl();
- if (!RD)
- return false;
- if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(RD))
- RD = CTSD->getSpecializedTemplate()->getTemplatedDecl();
- return RD->hasAttr<T>();
- }
-
- /// ....
- static bool isPointerLikeType(QualType Type);
+ static bool isPointerLikeType(QualType QT);
LifetimeCaptureByAttr *ParseLifetimeCaptureByAttr(const ParsedAttr &AL,
StringRef ParamName);
diff --git a/clang/lib/Sema/CheckExprLifetime.cpp b/clang/lib/Sema/CheckExprLifetime.cpp
index 6318e044ffdb77..7f069393a3a00f 100644
--- a/clang/lib/Sema/CheckExprLifetime.cpp
+++ b/clang/lib/Sema/CheckExprLifetime.cpp
@@ -9,6 +9,7 @@
#include "CheckExprLifetime.h"
#include "clang/AST/Decl.h"
#include "clang/AST/Expr.h"
+#include "clang/AST/Type.h"
#include "clang/Basic/DiagnosticSema.h"
#include "clang/Sema/Initialization.h"
#include "clang/Sema/Sema.h"
@@ -252,6 +253,24 @@ static void visitLocalsRetainedByReferenceBinding(IndirectLocalPath &Path,
Expr *Init, ReferenceKind RK,
LocalVisitor Visit);
+template <typename T> static bool isRecordWithAttr(QualType Type) {
+ auto *RD = Type->getAsCXXRecordDecl();
+ if (!RD)
+ return false;
+ if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(RD))
+ RD = CTSD->getSpecializedTemplate()->getTemplatedDecl();
+ return RD->hasAttr<T>();
+}
+} // namespace clang::sema
+
+namespace clang {
+bool Sema::isPointerLikeType(QualType QT) {
+ return sema::isRecordWithAttr<PointerAttr>(QT) || QT->isPointerType() ||
+ QT->isNullPtrType();
+}
+} // namespace clang
+
+namespace clang::sema {
// Decl::isInStdNamespace will return false for iterators in some STL
// implementations due to them being defined in a namespace outside of the std
// namespace.
@@ -292,7 +311,7 @@ static bool isContainerOfOwner(const RecordDecl *Container) {
return false;
const auto &TAs = CTSD->getTemplateArgs();
return TAs.size() > 0 && TAs[0].getKind() == TemplateArgument::Type &&
- Sema::isRecordWithAttr<OwnerAttr>(TAs[0].getAsType());
+ isRecordWithAttr<OwnerAttr>(TAs[0].getAsType());
}
// Returns true if the given Record is `std::initializer_list<pointer>`.
@@ -310,14 +329,14 @@ static bool isStdInitializerListOfPointer(const RecordDecl *RD) {
static bool shouldTrackImplicitObjectArg(const CXXMethodDecl *Callee) {
if (auto *Conv = dyn_cast_or_null<CXXConversionDecl>(Callee))
- if (Sema::isRecordWithAttr<PointerAttr>(Conv->getConversionType()) &&
+ if (isRecordWithAttr<PointerAttr>(Conv->getConversionType()) &&
Callee->getParent()->hasAttr<OwnerAttr>())
return true;
if (!isInStlNamespace(Callee->getParent()))
return false;
- if (!Sema::isRecordWithAttr<PointerAttr>(
+ if (!isRecordWithAttr<PointerAttr>(
Callee->getFunctionObjectParameterType()) &&
- !Sema::isRecordWithAttr<OwnerAttr>(
+ !isRecordWithAttr<OwnerAttr>(
Callee->getFunctionObjectParameterType()))
return false;
if (Sema::isPointerLikeType(Callee->getReturnType())) {
@@ -353,7 +372,7 @@ static bool shouldTrackFirstArgument(const FunctionDecl *FD) {
if (!RD->hasAttr<PointerAttr>() && !RD->hasAttr<OwnerAttr>())
return false;
if (FD->getReturnType()->isPointerType() ||
- Sema::isRecordWithAttr<PointerAttr>(FD->getReturnType())) {
+ isRecordWithAttr<PointerAttr>(FD->getReturnType())) {
return llvm::StringSwitch<bool>(FD->getName())
.Cases("begin", "rbegin", "cbegin", "crbegin", true)
.Cases("end", "rend", "cend", "crend", true)
@@ -425,7 +444,7 @@ shouldTrackFirstArgumentForConstructor(const CXXConstructExpr *Ctor) {
return true;
// RHS must be an owner.
- if (!Sema::isRecordWithAttr<OwnerAttr>(RHSArgType))
+ if (!isRecordWithAttr<OwnerAttr>(RHSArgType))
return false;
// Bail out if the RHS is Owner<Pointer>.
@@ -552,7 +571,7 @@ static void visitFunctionCallArguments(IndirectLocalPath &Path, Expr *Call,
// Once we initialized a value with a non gsl-owner reference, it can no
// longer dangle.
if (ReturnType->isReferenceType() &&
- !Sema::isRecordWithAttr<OwnerAttr>(ReturnType->getPointeeType())) {
+ !isRecordWithAttr<OwnerAttr>(ReturnType->getPointeeType())) {
for (const IndirectLocalPathEntry &PE : llvm::reverse(Path)) {
if (PE.Kind == IndirectLocalPathEntry::GslReferenceInit ||
PE.Kind == IndirectLocalPathEntry::LifetimeBoundCall)
@@ -1098,7 +1117,7 @@ static bool shouldRunGSLAssignmentAnalysis(const Sema &SemaRef,
bool EnableGSLAssignmentWarnings = !SemaRef.getDiagnostics().isIgnored(
diag::warn_dangling_lifetime_pointer_assignment, SourceLocation());
return (EnableGSLAssignmentWarnings &&
- (Sema::isRecordWithAttr<PointerAttr>(Entity.LHS->getType()) ||
+ (isRecordWithAttr<PointerAttr>(Entity.LHS->getType()) ||
isAssignmentOperatorLifetimeBound(Entity.AssignmentOperator)));
}
@@ -1133,12 +1152,12 @@ checkExprLifetimeImpl(Sema &SemaRef, const InitializedEntity *InitEntity,
// someContainer.add(std::move(localUniquePtr));
// return p;
if (pathContainsInit(Path) ||
- !Sema::isRecordWithAttr<OwnerAttr>(L->getType()))
+ !isRecordWithAttr<OwnerAttr>(L->getType()))
return false;
} else {
IsGslPtrValueFromGslTempOwner =
MTE && !MTE->getExtendingDecl() &&
- Sema::isRecordWithAttr<OwnerAttr>(MTE->getType());
+ isRecordWithAttr<OwnerAttr>(MTE->getType());
// Skipping a chain of initializing gsl::Pointer annotated objects.
// We are looking only for the final source to find out if it was
// a local or temporary owner or the address of a local variable/param.
@@ -1267,7 +1286,7 @@ checkExprLifetimeImpl(Sema &SemaRef, const InitializedEntity *InitEntity,
auto *DRE = dyn_cast<DeclRefExpr>(L);
// Suppress false positives for code like the one below:
// Ctor(unique_ptr<T> up) : pointer(up.get()), owner(move(up)) {}
- if (DRE && Sema::isRecordWithAttr<OwnerAttr>(DRE->getType()))
+ if (DRE && isRecordWithAttr<OwnerAttr>(DRE->getType()))
return false;
auto *VD = DRE ? dyn_cast<VarDecl>(DRE->getDecl()) : nullptr;
@@ -1490,4 +1509,4 @@ void checkCaptureByLifetime(Sema &SemaRef, const CapturingEntity &Entity,
/*CapEntity=*/&Entity, Init);
}
-} // namespace clang::sema
+} // namespace sema
diff --git a/clang/lib/Sema/SemaAttr.cpp b/clang/lib/Sema/SemaAttr.cpp
index 53a7387ad69353..f568ed277b0e9e 100644
--- a/clang/lib/Sema/SemaAttr.cpp
+++ b/clang/lib/Sema/SemaAttr.cpp
@@ -11,7 +11,6 @@
//
//===----------------------------------------------------------------------===//
-#include "CheckExprLifetime.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/Attr.h"
#include "clang/AST/Expr.h"
@@ -216,11 +215,6 @@ void Sema::inferGslOwnerPointerAttribute(CXXRecordDecl *Record) {
inferGslPointerAttribute(Record, Record);
}
-bool Sema::isPointerLikeType(QualType Type) {
- return isRecordWithAttr<PointerAttr>(Type) || Type->isPointerType() ||
- Type->isNullPtrType();
-}
-
void Sema::inferLifetimeBoundAttribute(FunctionDecl *FD) {
if (FD->getNumParams() == 0)
return;
>From a847f8bf8d02edb0b9615856713ec122cee1e927 Mon Sep 17 00:00:00 2001
From: Utkarsh Saxena <usx at google.com>
Date: Thu, 28 Nov 2024 10:46:49 +0000
Subject: [PATCH 5/5] fix namespace
---
clang/lib/Sema/CheckExprLifetime.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/lib/Sema/CheckExprLifetime.cpp b/clang/lib/Sema/CheckExprLifetime.cpp
index 7f069393a3a00f..f522c46c6c4388 100644
--- a/clang/lib/Sema/CheckExprLifetime.cpp
+++ b/clang/lib/Sema/CheckExprLifetime.cpp
@@ -1509,4 +1509,4 @@ void checkCaptureByLifetime(Sema &SemaRef, const CapturingEntity &Entity,
/*CapEntity=*/&Entity, Init);
}
-} // namespace sema
+} // namespace clang::sema
More information about the cfe-commits
mailing list