Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -643,6 +643,10 @@ Improvements to Clang's diagnostics
#GH142457, #GH139913, #GH138850, #GH137867, #GH137860, #GH107840, #GH93308,
#GH69470, #GH59391, #GH58172, #GH46215, #GH45915, #GH45891, #GH44490,
#GH36703, #GH32903, #GH23312, #GH69874.

- Clang no longer emits a spurious -Wdangling-gsl warning in C++23 when
iterating over an element of a temporary container in a range-based
for loop.(#GH109793, #GH145164)


Improvements to Clang's time-trace
Expand Down
19 changes: 19 additions & 0 deletions clang/include/clang/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -1085,6 +1085,11 @@ class VarDecl : public DeclaratorDecl, public Redeclarable<VarDecl> {

LLVM_PREFERRED_TYPE(bool)
unsigned IsCXXCondDecl : 1;

/// Whether this variable is the implicit __range variable in a for-range
/// loop.
LLVM_PREFERRED_TYPE(bool)
unsigned IsCXXForRangeImplicitVar : 1;
};

union {
Expand Down Expand Up @@ -1584,6 +1589,20 @@ class VarDecl : public DeclaratorDecl, public Redeclarable<VarDecl> {
NonParmVarDeclBits.IsCXXCondDecl = true;
}

/// Determine whether this variable is the compiler-generated '__range'
/// variable used to hold the range expression in a C++11 and later for-range
/// statement.
bool isCXXForRangeImplicitVar() const {
return isa<ParmVarDecl>(this) ? false
: NonParmVarDeclBits.IsCXXForRangeImplicitVar;
}

void setCXXForRangeImplicitVar(bool FRV) {
assert(!isa<ParmVarDecl>(this) &&
"Cannot set IsCXXForRangeImplicitVar on ParmVarDecl");
NonParmVarDeclBits.IsCXXForRangeImplicitVar = FRV;
}

/// Determines if this variable's alignment is dependent.
bool hasDependentAlignment() const;

Expand Down
8 changes: 8 additions & 0 deletions clang/lib/Sema/CheckExprLifetime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ enum LifetimeKind {
};
using LifetimeResult =
llvm::PointerIntPair<const InitializedEntity *, 3, LifetimeKind>;

} // namespace

/// Determine the declaration which an initialized entity ultimately refers to,
Expand Down Expand Up @@ -1341,6 +1342,13 @@ checkExprLifetimeImpl(Sema &SemaRef, const InitializedEntity *InitEntity,
}

if (IsGslPtrValueFromGslTempOwner && DiagLoc.isValid()) {

if (SemaRef.getLangOpts().CPlusPlus23) {
if (const VarDecl *VD = cast<VarDecl>(InitEntity->getDecl());
VD && VD->isCXXForRangeImplicitVar())
return false;
}

SemaRef.Diag(DiagLoc, diag::warn_dangling_lifetime_pointer)
<< DiagRange;
return false;
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/Sema/SemaStmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2374,6 +2374,9 @@ static bool FinishForRangeVarDecl(Sema &SemaRef, VarDecl *Decl, Expr *Init,
SemaRef.ObjC().inferObjCARCLifetime(Decl))
Decl->setInvalidDecl();

if (SemaRef.getLangOpts().CPlusPlus23)
SemaRef.currentEvaluationContext().InLifetimeExtendingContext = true;

SemaRef.AddInitializerToDecl(Decl, Init, /*DirectInit=*/false);
SemaRef.FinalizeDeclaration(Decl);
SemaRef.CurContext->addHiddenDecl(Decl);
Expand Down Expand Up @@ -2423,6 +2426,7 @@ VarDecl *BuildForRangeVarDecl(Sema &SemaRef, SourceLocation Loc,
VarDecl *Decl = VarDecl::Create(SemaRef.Context, DC, Loc, Loc, II, Type,
TInfo, SC_None);
Decl->setImplicit();
Decl->setCXXForRangeImplicitVar(true);
return Decl;
}

Expand Down
1 change: 1 addition & 0 deletions clang/lib/Serialization/ASTReaderDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1637,6 +1637,7 @@ RedeclarableResult ASTDeclReader::VisitVarDeclImpl(VarDecl *VD) {
VarDeclBits.getNextBits(/*Width*/ 3);

VD->NonParmVarDeclBits.ObjCForDecl = VarDeclBits.getNextBit();
VD->NonParmVarDeclBits.IsCXXForRangeImplicitVar = VarDeclBits.getNextBit();
}

// If this variable has a deduced type, defer reading that type until we are
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/Serialization/ASTWriterDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1319,6 +1319,7 @@ void ASTDeclWriter::VisitVarDecl(VarDecl *D) {
VarDeclBits.addBits(0, /*Width=*/3);

VarDeclBits.addBit(D->isObjCForDecl());
VarDeclBits.addBit(D->isCXXForRangeImplicitVar());
}

Record.push_back(VarDeclBits);
Expand Down Expand Up @@ -2740,6 +2741,7 @@ void ASTWriter::WriteDeclAbbrevs() {
// isInline, isInlineSpecified, isConstexpr,
// isInitCapture, isPrevDeclInSameScope, hasInitWithSideEffects,
// EscapingByref, HasDeducedType, ImplicitParamKind, isObjCForDecl
// IsCXXForRangeImplicitVar
Abv->Add(BitCodeAbbrevOp(0)); // VarKind (local enum)
// Type Source Info
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array));
Expand Down
27 changes: 27 additions & 0 deletions clang/test/SemaCXX/range-for-lifetime-cxx23.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// RUN: %clang_cc1 -std=c++23 -fsyntax-only -verify %s

using size_t = decltype(sizeof(void *));

namespace std {
template <typename T> struct vector {
T &operator[](size_t I);
};

struct string {
const char *begin();
const char *end();
};

} // namespace std

std::vector<std::string> getData();

void foo() {
// Verifies we don't trigger a diagnostic from -Wdangling-gsl
// when iterating over a temporary in C++23.
for (auto c : getData()[0]) {
(void)c;
}
}

// expected-no-diagnostics
Loading