cor3ntin updated this revision to Diff 472581.
cor3ntin added a comment.
Forgot to clang-format!
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D137244/new/
https://reviews.llvm.org/D137244
Files:
clang/include/clang/AST/Decl.h
clang/include/clang/Sema/ScopeInfo.h
clang/include/clang/Sema/Sema.h
clang/include/clang/Sema/SemaLambda.h
clang/lib/AST/DeclCXX.cpp
clang/lib/Sema/ScopeInfo.cpp
clang/lib/Sema/SemaExpr.cpp
clang/lib/Sema/SemaExprCXX.cpp
clang/lib/Sema/SemaLambda.cpp
clang/lib/Sema/TreeTransform.h
clang/test/SemaCXX/cxx20-decomposition.cpp
Index: clang/test/SemaCXX/cxx20-decomposition.cpp
===================================================================
--- clang/test/SemaCXX/cxx20-decomposition.cpp
+++ clang/test/SemaCXX/cxx20-decomposition.cpp
@@ -1,5 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -std=c++20 -verify %s
-// expected-no-diagnostics
+// RUN: %clang_cc1 -fsyntax-only -std=c++20 -verify -Wunused-variable %s
template <typename, typename>
constexpr bool is_same = false;
@@ -80,10 +79,21 @@
namespace std {
template <typename T>
-struct tuple_size {
+struct tuple_size;
+
+template <typename T>
+struct tuple_size<T&> : tuple_size<T>{};
+
+template <typename T>
+requires requires { tuple_size<T>::value; }
+struct tuple_size<const T> : tuple_size<T>{};
+
+template <>
+struct tuple_size<tuple> {
static constexpr unsigned long value = 2;
};
+
template <unsigned long, typename T>
struct tuple_element;
@@ -139,3 +149,37 @@
};
}
}
+
+namespace ODRUseTests {
+ struct P { int a; int b; };
+ void GH57826() {
+ const auto [a, b] = P{1, 2}; //expected-note 2{{'b' declared here}} \
+ //expected-note 3{{'a' declared here}}
+ (void)[&](auto c) { return b + [&a] {
+ return a;
+ }() ; }(0);
+ (void)[&](auto c) { return b + [&a](auto) {
+ return a;
+ }(0) ; }(0);
+ (void)[=](auto c) { return b + [&a](auto) {
+ return a;
+ }(0) ; }(0);
+ (void)[&a,&b](auto c) { return b + [&a](auto) {
+ return a;
+ }(0) ; }(0);
+ (void)[&a,&b](auto c) { return b + [a](auto) {
+ return a;
+ }(0) ; }(0);
+ (void)[&a](auto c) { return b + [&a](auto) { // expected-error 2{{variable 'b' cannot be implicitly captured}} \
+ // expected-note 2{{lambda expression begins here}} \
+ // expected-note 4{{capture 'b'}}
+ return a;
+ }(0) ; }(0); // expected-note {{in instantiation}}
+ (void)[&b](auto c) { return b + [](auto) { // expected-note 3{{lambda expression begins here}} \
+ // expected-note 6{{capture 'a'}} \
+ // expected-note 6{{default capture}} \
+ // expected-note {{in instantiation}}
+ return a; // expected-error 3{{variable 'a' cannot be implicitly captured}}
+ }(0) ; }(0); // expected-note 2{{in instantiation}}
+ }
+}
Index: clang/lib/Sema/TreeTransform.h
===================================================================
--- clang/lib/Sema/TreeTransform.h
+++ clang/lib/Sema/TreeTransform.h
@@ -13312,9 +13312,8 @@
}
// Transform the captured variable.
- VarDecl *CapturedVar
- = cast_or_null<VarDecl>(getDerived().TransformDecl(C->getLocation(),
- C->getCapturedVar()));
+ ValueDecl *CapturedVar = cast_or_null<ValueDecl>(
+ getDerived().TransformDecl(C->getLocation(), C->getCapturedVar()));
if (!CapturedVar || CapturedVar->isInvalidDecl()) {
Invalid = true;
continue;
Index: clang/lib/Sema/SemaLambda.cpp
===================================================================
--- clang/lib/Sema/SemaLambda.cpp
+++ clang/lib/Sema/SemaLambda.cpp
@@ -62,7 +62,7 @@
static inline Optional<unsigned>
getStackIndexOfNearestEnclosingCaptureReadyLambda(
ArrayRef<const clang::sema::FunctionScopeInfo *> FunctionScopes,
- VarDecl *VarToCapture) {
+ ValueDecl *VarToCapture) {
// Label failure to capture.
const Optional<unsigned> NoLambdaIsCaptureReady;
@@ -172,7 +172,7 @@
Optional<unsigned> clang::getStackIndexOfNearestEnclosingCaptureCapableLambda(
ArrayRef<const sema::FunctionScopeInfo *> FunctionScopes,
- VarDecl *VarToCapture, Sema &S) {
+ ValueDecl *VarToCapture, Sema &S) {
const Optional<unsigned> NoLambdaIsCaptureCapable;
Index: clang/lib/Sema/SemaExprCXX.cpp
===================================================================
--- clang/lib/Sema/SemaExprCXX.cpp
+++ clang/lib/Sema/SemaExprCXX.cpp
@@ -8223,7 +8223,7 @@
// All the potentially captureable variables in the current nested
// lambda (within a generic outer lambda), must be captured by an
// outer lambda that is enclosed within a non-dependent context.
- CurrentLSI->visitPotentialCaptures([&] (VarDecl *Var, Expr *VarExpr) {
+ CurrentLSI->visitPotentialCaptures([&](ValueDecl *Var, Expr *VarExpr) {
// If the variable is clearly identified as non-odr-used and the full
// expression is not instantiation dependent, only then do we not
// need to check enclosing lambda's for speculative captures.
@@ -8239,6 +8239,10 @@
!IsFullExprInstantiationDependent)
return;
+ VarDecl *UnderlyingVar = Var->getPotentiallyDecomposedVarDecl();
+ if (!UnderlyingVar)
+ return;
+
// If we have a capture-capable lambda for the variable, go ahead and
// capture the variable in that lambda (and all its enclosing lambdas).
if (const Optional<unsigned> Index =
@@ -8246,7 +8250,7 @@
S.FunctionScopes, Var, S))
S.MarkCaptureUsedInEnclosingContext(Var, VarExpr->getExprLoc(), *Index);
const bool IsVarNeverAConstantExpression =
- VariableCanNeverBeAConstantExpression(Var, S.Context);
+ VariableCanNeverBeAConstantExpression(UnderlyingVar, S.Context);
if (!IsFullExprInstantiationDependent || IsVarNeverAConstantExpression) {
// This full expression is not instantiation dependent or the variable
// can not be used in a constant expression - which means
Index: clang/lib/Sema/SemaExpr.cpp
===================================================================
--- clang/lib/Sema/SemaExpr.cpp
+++ clang/lib/Sema/SemaExpr.cpp
@@ -18229,10 +18229,13 @@
/// - else capture it in the DeclContext that maps to the
/// *FunctionScopeIndexToStopAt on the FunctionScopeInfo stack.
static void
-MarkVarDeclODRUsed(VarDecl *Var, SourceLocation Loc, Sema &SemaRef,
+MarkVarDeclODRUsed(ValueDecl *V, SourceLocation Loc, Sema &SemaRef,
const unsigned *const FunctionScopeIndexToStopAt = nullptr) {
// Keep track of used but undefined variables.
// FIXME: We shouldn't suppress this warning for static data members.
+ VarDecl *Var = V->getPotentiallyDecomposedVarDecl();
+ assert(Var && "expected a capturable variable");
+
if (Var->hasDefinition(SemaRef.Context) == VarDecl::DeclarationOnly &&
(!Var->isExternallyVisible() || Var->isInline() ||
SemaRef.isExternalWithNoLinkageType(Var)) &&
@@ -18243,12 +18246,11 @@
}
QualType CaptureType, DeclRefType;
if (SemaRef.LangOpts.OpenMP)
- SemaRef.tryCaptureOpenMPLambdas(Var);
- SemaRef.tryCaptureVariable(Var, Loc, Sema::TryCapture_Implicit,
- /*EllipsisLoc*/ SourceLocation(),
- /*BuildAndDiagnose*/ true,
- CaptureType, DeclRefType,
- FunctionScopeIndexToStopAt);
+ SemaRef.tryCaptureOpenMPLambdas(V);
+ SemaRef.tryCaptureVariable(V, Loc, Sema::TryCapture_Implicit,
+ /*EllipsisLoc*/ SourceLocation(),
+ /*BuildAndDiagnose*/ true, CaptureType,
+ DeclRefType, FunctionScopeIndexToStopAt);
if (SemaRef.LangOpts.CUDA && Var->hasGlobalStorage()) {
auto *FD = dyn_cast_or_null<FunctionDecl>(SemaRef.CurContext);
@@ -18288,10 +18290,10 @@
}
}
- Var->markUsed(SemaRef.Context);
+ V->markUsed(SemaRef.Context);
}
-void Sema::MarkCaptureUsedInEnclosingContext(VarDecl *Capture,
+void Sema::MarkCaptureUsedInEnclosingContext(ValueDecl *Capture,
SourceLocation Loc,
unsigned CapturingScopeIndex) {
MarkVarDeclODRUsed(Capture, Loc, *this, &CapturingScopeIndex);
@@ -18800,8 +18802,7 @@
if (VD->isInitCapture())
VarDC = VarDC->getParent();
} else {
- VD = dyn_cast<DecompositionDecl>(
- cast<BindingDecl>(Var)->getDecomposedDecl());
+ VD = Var->getPotentiallyDecomposedVarDecl();
}
assert(VD && "Cannot capture a null variable");
@@ -19475,6 +19476,38 @@
"MarkVarDeclODRUsed failed to cleanup MaybeODRUseExprs?");
}
+static void DoMarkPotentialCapture(Sema &SemaRef, SourceLocation Loc,
+ ValueDecl *Var, Expr *E) {
+ VarDecl *VD = Var->getPotentiallyDecomposedVarDecl();
+ if (!VD)
+ return;
+
+ const bool RefersToEnclosingScope =
+ (SemaRef.CurContext != VD->getDeclContext() &&
+ VD->getDeclContext()->isFunctionOrMethod() && VD->hasLocalStorage());
+ if (RefersToEnclosingScope) {
+ LambdaScopeInfo *const LSI =
+ SemaRef.getCurLambda(/*IgnoreNonLambdaCapturingScope=*/true);
+ if (LSI && (!LSI->CallOperator ||
+ !LSI->CallOperator->Encloses(Var->getDeclContext()))) {
+ // If a variable could potentially be odr-used, defer marking it so
+ // until we finish analyzing the full expression for any
+ // lvalue-to-rvalue
+ // or discarded value conversions that would obviate odr-use.
+ // Add it to the list of potential captures that will be analyzed
+ // later (ActOnFinishFullExpr) for eventual capture and odr-use marking
+ // unless the variable is a reference that was initialized by a constant
+ // expression (this will never need to be captured or odr-used).
+ //
+ // FIXME: We can simplify this a lot after implementing P0588R1.
+ assert(E && "Capture variable should be used in an expression.");
+ if (!Var->getType()->isReferenceType() ||
+ !VD->isUsableInConstantExpressions(SemaRef.Context))
+ LSI->addPotentialCapture(E->IgnoreParens());
+ }
+ }
+}
+
static void DoMarkVarDeclReferenced(
Sema &SemaRef, SourceLocation Loc, VarDecl *Var, Expr *E,
llvm::DenseMap<const VarDecl *, int> &RefsMinusAssignments) {
@@ -19621,36 +19654,13 @@
// odr-used, but we may still need to track them for lambda capture.
// FIXME: Do we also need to do this inside dependent typeid expressions
// (which are modeled as unevaluated at this point)?
- const bool RefersToEnclosingScope =
- (SemaRef.CurContext != Var->getDeclContext() &&
- Var->getDeclContext()->isFunctionOrMethod() && Var->hasLocalStorage());
- if (RefersToEnclosingScope) {
- LambdaScopeInfo *const LSI =
- SemaRef.getCurLambda(/*IgnoreNonLambdaCapturingScope=*/true);
- if (LSI && (!LSI->CallOperator ||
- !LSI->CallOperator->Encloses(Var->getDeclContext()))) {
- // If a variable could potentially be odr-used, defer marking it so
- // until we finish analyzing the full expression for any
- // lvalue-to-rvalue
- // or discarded value conversions that would obviate odr-use.
- // Add it to the list of potential captures that will be analyzed
- // later (ActOnFinishFullExpr) for eventual capture and odr-use marking
- // unless the variable is a reference that was initialized by a constant
- // expression (this will never need to be captured or odr-used).
- //
- // FIXME: We can simplify this a lot after implementing P0588R1.
- assert(E && "Capture variable should be used in an expression.");
- if (!Var->getType()->isReferenceType() ||
- !Var->isUsableInConstantExpressions(SemaRef.Context))
- LSI->addPotentialCapture(E->IgnoreParens());
- }
- }
+ DoMarkPotentialCapture(SemaRef, Loc, Var, E);
break;
}
}
static void DoMarkBindingDeclReferenced(Sema &SemaRef, SourceLocation Loc,
- BindingDecl *BD) {
+ BindingDecl *BD, Expr *E) {
BD->setReferenced();
if (BD->isInvalidDecl())
@@ -19664,6 +19674,8 @@
/*BuildAndDiagnose*/ true, CaptureType,
DeclRefType,
/*FunctionScopeIndexToStopAt*/ nullptr);
+ } else if (OdrUse == OdrUseContext::Dependent) {
+ DoMarkPotentialCapture(SemaRef, Loc, BD, E);
}
}
@@ -19687,7 +19699,7 @@
}
if (BindingDecl *Decl = dyn_cast<BindingDecl>(D)) {
- DoMarkBindingDeclReferenced(SemaRef, Loc, Decl);
+ DoMarkBindingDeclReferenced(SemaRef, Loc, Decl, E);
return;
}
Index: clang/lib/Sema/ScopeInfo.cpp
===================================================================
--- clang/lib/Sema/ScopeInfo.cpp
+++ clang/lib/Sema/ScopeInfo.cpp
@@ -231,14 +231,14 @@
}
void LambdaScopeInfo::visitPotentialCaptures(
- llvm::function_ref<void(VarDecl *, Expr *)> Callback) const {
+ llvm::function_ref<void(ValueDecl *, Expr *)> Callback) const {
for (Expr *E : PotentiallyCapturingExprs) {
if (auto *DRE = dyn_cast<DeclRefExpr>(E)) {
- Callback(cast<VarDecl>(DRE->getFoundDecl()), E);
+ Callback(cast<ValueDecl>(DRE->getFoundDecl()), E);
} else if (auto *ME = dyn_cast<MemberExpr>(E)) {
- Callback(cast<VarDecl>(ME->getMemberDecl()), E);
+ Callback(cast<ValueDecl>(ME->getMemberDecl()), E);
} else if (auto *FP = dyn_cast<FunctionParmPackExpr>(E)) {
- for (VarDecl *VD : *FP)
+ for (ValueDecl *VD : *FP)
Callback(VD, E);
} else {
llvm_unreachable("unexpected expression in potential captures list");
Index: clang/lib/AST/DeclCXX.cpp
===================================================================
--- clang/lib/AST/DeclCXX.cpp
+++ clang/lib/AST/DeclCXX.cpp
@@ -3228,6 +3228,16 @@
nullptr, SourceLocation(), false);
}
+VarDecl *ValueDecl::getPotentiallyDecomposedVarDecl() {
+ assert((isa<VarDecl>(this) || isa<BindingDecl>(this)) &&
+ "expected a VarDecl or a BindingDecl");
+ if (auto *Var = llvm::dyn_cast<VarDecl>(this))
+ return Var;
+ if (auto *BD = llvm::dyn_cast<BindingDecl>(this))
+ return llvm::dyn_cast<VarDecl>(BD->getDecomposedDecl());
+ return nullptr;
+}
+
void BindingDecl::anchor() {}
BindingDecl *BindingDecl::Create(ASTContext &C, DeclContext *DC,
Index: clang/include/clang/Sema/SemaLambda.h
===================================================================
--- clang/include/clang/Sema/SemaLambda.h
+++ clang/include/clang/Sema/SemaLambda.h
@@ -32,7 +32,7 @@
Optional<unsigned> getStackIndexOfNearestEnclosingCaptureCapableLambda(
ArrayRef<const sema::FunctionScopeInfo *> FunctionScopes,
- VarDecl *VarToCapture, Sema &S);
+ ValueDecl *VarToCapture, Sema &S);
} // clang
Index: clang/include/clang/Sema/Sema.h
===================================================================
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -5370,7 +5370,7 @@
void MarkDeclRefReferenced(DeclRefExpr *E, const Expr *Base = nullptr);
void MarkMemberReferenced(MemberExpr *E);
void MarkFunctionParmPackReferenced(FunctionParmPackExpr *E);
- void MarkCaptureUsedInEnclosingContext(VarDecl *Capture, SourceLocation Loc,
+ void MarkCaptureUsedInEnclosingContext(ValueDecl *Capture, SourceLocation Loc,
unsigned CapturingScopeIndex);
ExprResult CheckLValueToRValueConversionOperand(Expr *E);
Index: clang/include/clang/Sema/ScopeInfo.h
===================================================================
--- clang/include/clang/Sema/ScopeInfo.h
+++ clang/include/clang/Sema/ScopeInfo.h
@@ -1028,7 +1028,7 @@
}
void visitPotentialCaptures(
- llvm::function_ref<void(VarDecl *, Expr *)> Callback) const;
+ llvm::function_ref<void(ValueDecl *, Expr *)> Callback) const;
};
FunctionScopeInfo::WeakObjectProfileTy::WeakObjectProfileTy()
Index: clang/include/clang/AST/Decl.h
===================================================================
--- clang/include/clang/AST/Decl.h
+++ clang/include/clang/AST/Decl.h
@@ -670,6 +670,8 @@
}
};
+class VarDecl;
+
/// Represent the declaration of a variable (in which case it is
/// an lvalue) a function (in which case it is a function designator) or
/// an enum constant.
@@ -696,6 +698,10 @@
/// can be captured.
bool isInitCapture() const;
+ // If this is a VarDecl, or a BindindDecl with an
+ // associated decomposed VarDecl, return that VarDecl.
+ VarDecl *getPotentiallyDecomposedVarDecl();
+
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classofKind(Kind K) { return K >= firstValue && K <= lastValue; }
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits