From: Corentin Jabot Date: Wed, 3 Aug 2022 18:59:36 +0000 (+0200) Subject: Revert "[Clang][C++20] Support capturing structured bindings in lambdas" X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=a274219600ea00c4406248acfbea113e29a8ead2;p=platform%2Fupstream%2Fllvm.git Revert "[Clang][C++20] Support capturing structured bindings in lambdas" This reverts commit 44f2baa3804a62ca793f0ff3e43aa71cea91a795. Breaks self builds and seems to have conformance issues. --- diff --git a/clang-tools-extra/clang-tidy/modernize/LoopConvertUtils.cpp b/clang-tools-extra/clang-tidy/modernize/LoopConvertUtils.cpp index fc3dfbd..5d4f3b8 100644 --- a/clang-tools-extra/clang-tidy/modernize/LoopConvertUtils.cpp +++ b/clang-tools-extra/clang-tidy/modernize/LoopConvertUtils.cpp @@ -785,8 +785,8 @@ bool ForLoopIndexUseVisitor::TraverseLambdaCapture(LambdaExpr *LE, const LambdaCapture *C, Expr *Init) { if (C->capturesVariable()) { - const ValueDecl *VDecl = C->getCapturedVar(); - if (areSameVariable(IndexVar, VDecl)) { + const VarDecl *VDecl = C->getCapturedVar(); + if (areSameVariable(IndexVar, cast(VDecl))) { // FIXME: if the index is captured, it will count as an usage and the // alias (if any) won't work, because it is only used in case of having // exactly one usage. diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index e42ed9d..dd0d802 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -108,16 +108,6 @@ C++ Language Changes in Clang C++20 Feature Support ^^^^^^^^^^^^^^^^^^^^^ -- Support capturing structured bindings in lambdas - (`P1091R3 `_ and `P1381R1 `). - This fixes issues `GH52720 `_, - `GH54300 `_, - `GH54301 `_, - and `GH49430 `_. - - - - C++2b Feature Support ^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h index 1b414b5..6441cd3 100644 --- a/clang/include/clang/AST/Decl.h +++ b/clang/include/clang/AST/Decl.h @@ -689,11 +689,6 @@ public: /// or declared with the weak or weak-ref attr. bool isWeak() const; - /// Whether this variable is the implicit variable for a lambda init-capture. - /// Only VarDecl can be init captures, but both VarDecl and BindingDecl - /// can be captured. - bool isInitCapture() const; - // 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; } diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h index c973019..9e4fc3f 100644 --- a/clang/include/clang/AST/DeclCXX.h +++ b/clang/include/clang/AST/DeclCXX.h @@ -1057,9 +1057,8 @@ public: /// /// \note No entries will be added for init-captures, as they do not capture /// variables. - void - getCaptureFields(llvm::DenseMap &Captures, - FieldDecl *&ThisCapture) const; + void getCaptureFields(llvm::DenseMap &Captures, + FieldDecl *&ThisCapture) const; using capture_const_iterator = const LambdaCapture *; using capture_const_range = llvm::iterator_range; diff --git a/clang/include/clang/AST/LambdaCapture.h b/clang/include/clang/AST/LambdaCapture.h index 62e7716..7ad1e23 100644 --- a/clang/include/clang/AST/LambdaCapture.h +++ b/clang/include/clang/AST/LambdaCapture.h @@ -71,7 +71,7 @@ public: /// capture that is a pack expansion, or an invalid source /// location to indicate that this is not a pack expansion. LambdaCapture(SourceLocation Loc, bool Implicit, LambdaCaptureKind Kind, - ValueDecl *Var = nullptr, + VarDecl *Var = nullptr, SourceLocation EllipsisLoc = SourceLocation()); /// Determine the kind of capture. @@ -86,7 +86,7 @@ public: /// Determine whether this capture handles a variable. bool capturesVariable() const { - return isa_and_nonnull(DeclAndBits.getPointer()); + return isa_and_nonnull(DeclAndBits.getPointer()); } /// Determine whether this captures a variable length array bound @@ -101,9 +101,9 @@ public: /// /// This operation is only valid if this capture is a variable capture /// (other than a capture of \c this). - ValueDecl *getCapturedVar() const { + VarDecl *getCapturedVar() const { assert(capturesVariable() && "No variable available for capture"); - return static_cast(DeclAndBits.getPointer()); + return static_cast(DeclAndBits.getPointer()); } /// Determine whether this was an implicit capture (not diff --git a/clang/include/clang/AST/Stmt.h b/clang/include/clang/AST/Stmt.h index 52c0ca5..49a66a1 100644 --- a/clang/include/clang/AST/Stmt.h +++ b/clang/include/clang/AST/Stmt.h @@ -59,7 +59,6 @@ class RecordDecl; class SourceManager; class StringLiteral; class Token; -class ValueDecl; class VarDecl; //===----------------------------------------------------------------------===// diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h index 5bcf1d3..9f4d807 100644 --- a/clang/include/clang/ASTMatchers/ASTMatchers.h +++ b/clang/include/clang/ASTMatchers/ASTMatchers.h @@ -4722,7 +4722,7 @@ AST_MATCHER_P(LambdaExpr, hasAnyCapture, internal::Matcher, /// In the matcher /// lambdaExpr(hasAnyCapture(lambdaCapture(capturesVar(hasName("x")))), /// capturesVar(hasName("x")) matches `x` and `x = 1`. -AST_MATCHER_P(LambdaCapture, capturesVar, internal::Matcher, +AST_MATCHER_P(LambdaCapture, capturesVar, internal::Matcher, InnerMatcher) { auto *capturedVar = Node.getCapturedVar(); return capturedVar && InnerMatcher.matches(*capturedVar, Finder, Builder); diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 550ad5a..6ff5b8d 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -9013,16 +9013,6 @@ def ext_ms_anonymous_record : ExtWarn< def err_reference_to_local_in_enclosing_context : Error< "reference to local %select{variable|binding}1 %0 declared in enclosing " "%select{%3|block literal|lambda expression|context}2">; -def err_bitfield_capture_by_ref : Error< - "cannot capture a bit-field by reference">; -def err_capture_binding_openmp : Error< - "capturing a structured binding is not yet supported in OpenMP">; -def ext_capture_binding : ExtWarn< - "captured structured bindings are a C++20 extension">, InGroup; -def warn_cxx17_compat_capture_binding : Warning< - "captured structured bindings are incompatible with " - "C++ standards before C++20">, - InGroup, DefaultIgnore; def err_static_data_member_not_allowed_in_local_class : Error< "static data member %0 not allowed in local %sub{select_tag_type_kind}2 %1">; diff --git a/clang/include/clang/Sema/ScopeInfo.h b/clang/include/clang/Sema/ScopeInfo.h index c0dfcb8..18848c8d 100644 --- a/clang/include/clang/Sema/ScopeInfo.h +++ b/clang/include/clang/Sema/ScopeInfo.h @@ -553,7 +553,7 @@ class Capture { const VariableArrayType *CapturedVLA; /// Otherwise, the captured variable (if any). - ValueDecl *CapturedVar; + VarDecl *CapturedVar; }; /// The source location at which the first capture occurred. @@ -589,13 +589,12 @@ class Capture { unsigned Invalid : 1; public: - Capture(ValueDecl *Var, bool Block, bool ByRef, bool IsNested, + Capture(VarDecl *Var, bool Block, bool ByRef, bool IsNested, SourceLocation Loc, SourceLocation EllipsisLoc, QualType CaptureType, bool Invalid) : CapturedVar(Var), Loc(Loc), EllipsisLoc(EllipsisLoc), - CaptureType(CaptureType), Kind(Block ? Cap_Block - : ByRef ? Cap_ByRef - : Cap_ByCopy), + CaptureType(CaptureType), + Kind(Block ? Cap_Block : ByRef ? Cap_ByRef : Cap_ByCopy), Nested(IsNested), CapturesThis(false), ODRUsed(false), NonODRUsed(false), Invalid(Invalid) {} @@ -640,7 +639,7 @@ public: NonODRUsed = true; } - ValueDecl *getVariable() const { + VarDecl *getVariable() const { assert(isVariableCapture()); return CapturedVar; } @@ -679,7 +678,7 @@ public: : FunctionScopeInfo(Diag), ImpCaptureStyle(Style) {} /// CaptureMap - A map of captured variables to (index+1) into Captures. - llvm::DenseMap CaptureMap; + llvm::DenseMap CaptureMap; /// CXXThisCaptureIndex - The (index+1) of the capture of 'this'; /// zero if 'this' is not captured. @@ -696,7 +695,7 @@ public: /// or null if unknown. QualType ReturnType; - void addCapture(ValueDecl *Var, bool isBlock, bool isByref, bool isNested, + void addCapture(VarDecl *Var, bool isBlock, bool isByref, bool isNested, SourceLocation Loc, SourceLocation EllipsisLoc, QualType CaptureType, bool Invalid) { Captures.push_back(Capture(Var, isBlock, isByref, isNested, Loc, @@ -723,21 +722,23 @@ public: } /// Determine whether the given variable has been captured. - bool isCaptured(ValueDecl *Var) const { return CaptureMap.count(Var); } + bool isCaptured(VarDecl *Var) const { + return CaptureMap.count(Var); + } /// Determine whether the given variable-array type has been captured. bool isVLATypeCaptured(const VariableArrayType *VAT) const; /// Retrieve the capture of the given variable, if it has been /// captured already. - Capture &getCapture(ValueDecl *Var) { + Capture &getCapture(VarDecl *Var) { assert(isCaptured(Var) && "Variable has not been captured"); return Captures[CaptureMap[Var] - 1]; } - const Capture &getCapture(ValueDecl *Var) const { - llvm::DenseMap::const_iterator Known = - CaptureMap.find(Var); + const Capture &getCapture(VarDecl *Var) const { + llvm::DenseMap::const_iterator Known + = CaptureMap.find(Var); assert(Known != CaptureMap.end() && "Variable has not been captured"); return Captures[Known->second - 1]; } diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 706383e..ed50b9e 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -5325,23 +5325,23 @@ public: /// /// \returns true if an error occurred (i.e., the variable cannot be /// captured) and false if the capture succeeded. - bool tryCaptureVariable(ValueDecl *Var, SourceLocation Loc, - TryCaptureKind Kind, SourceLocation EllipsisLoc, - bool BuildAndDiagnose, QualType &CaptureType, + bool tryCaptureVariable(VarDecl *Var, SourceLocation Loc, TryCaptureKind Kind, + SourceLocation EllipsisLoc, bool BuildAndDiagnose, + QualType &CaptureType, QualType &DeclRefType, const unsigned *const FunctionScopeIndexToStopAt); /// Try to capture the given variable. - bool tryCaptureVariable(ValueDecl *Var, SourceLocation Loc, + bool tryCaptureVariable(VarDecl *Var, SourceLocation Loc, TryCaptureKind Kind = TryCapture_Implicit, SourceLocation EllipsisLoc = SourceLocation()); /// Checks if the variable must be captured. - bool NeedToCaptureVariable(ValueDecl *Var, SourceLocation Loc); + bool NeedToCaptureVariable(VarDecl *Var, SourceLocation Loc); /// Given a variable, determine the type that a reference to that /// variable will have in the given scope. - QualType getCapturedDeclRefType(ValueDecl *Var, SourceLocation Loc); + QualType getCapturedDeclRefType(VarDecl *Var, SourceLocation Loc); /// Mark all of the declarations referenced within a particular AST node as /// referenced. Used when template instantiation instantiates a non-dependent diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index 2e23092..1590107 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -1006,7 +1006,7 @@ ASTNodeImporter::import(const Designator &D) { template <> Expected ASTNodeImporter::import(const LambdaCapture &From) { - ValueDecl *Var = nullptr; + VarDecl *Var = nullptr; if (From.capturesVariable()) { if (auto VarOrErr = import(From.getCapturedVar())) Var = *VarOrErr; diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index 6168868..030792b 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -4983,12 +4983,6 @@ bool ValueDecl::isWeak() const { MostRecent->hasAttr() || isWeakImported(); } -bool ValueDecl::isInitCapture() const { - if (auto *Var = llvm::dyn_cast(this)) - return Var->isInitCapture(); - return false; -} - void ImplicitParamDecl::anchor() {} ImplicitParamDecl *ImplicitParamDecl::Create(ASTContext &C, DeclContext *DC, diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp index 38c46b1..a955b4f 100644 --- a/clang/lib/AST/DeclCXX.cpp +++ b/clang/lib/AST/DeclCXX.cpp @@ -1570,8 +1570,8 @@ CXXMethodDecl *CXXRecordDecl::getLambdaStaticInvoker(CallingConv CC) const { } void CXXRecordDecl::getCaptureFields( - llvm::DenseMap &Captures, - FieldDecl *&ThisCapture) const { + llvm::DenseMap &Captures, + FieldDecl *&ThisCapture) const { Captures.clear(); ThisCapture = nullptr; diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp index 1f860a3..6328fa4 100644 --- a/clang/lib/AST/ExprCXX.cpp +++ b/clang/lib/AST/ExprCXX.cpp @@ -1087,7 +1087,7 @@ CXXConstructExpr::CXXConstructExpr(StmtClass SC, EmptyShell Empty, : Expr(SC, Empty), NumArgs(NumArgs) {} LambdaCapture::LambdaCapture(SourceLocation Loc, bool Implicit, - LambdaCaptureKind Kind, ValueDecl *Var, + LambdaCaptureKind Kind, VarDecl *Var, SourceLocation EllipsisLoc) : DeclAndBits(Var, 0), Loc(Loc), EllipsisLoc(EllipsisLoc) { unsigned Bits = 0; @@ -1211,8 +1211,8 @@ const CompoundStmt *LambdaExpr::getCompoundStmtBody() const { } bool LambdaExpr::isInitCapture(const LambdaCapture *C) const { - return C->capturesVariable() && C->getCapturedVar()->isInitCapture() && - getCallOperator() == C->getCapturedVar()->getDeclContext(); + return (C->capturesVariable() && C->getCapturedVar()->isInitCapture() && + (getCallOperator() == C->getCapturedVar()->getDeclContext())); } LambdaExpr::capture_iterator LambdaExpr::capture_begin() const { diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 6f3539a..efaccf5 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -578,7 +578,7 @@ namespace { /// LambdaCaptureFields - Mapping from captured variables/this to /// corresponding data members in the closure class. - llvm::DenseMap LambdaCaptureFields; + llvm::DenseMap LambdaCaptureFields; FieldDecl *LambdaThisCaptureField; CallStackFrame(EvalInfo &Info, SourceLocation CallLoc, diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp index 9cb72ee..8d77850 100644 --- a/clang/lib/AST/StmtPrinter.cpp +++ b/clang/lib/AST/StmtPrinter.cpp @@ -2164,8 +2164,7 @@ void StmtPrinter::VisitLambdaExpr(LambdaExpr *Node) { OS << "..."; if (Node->isInitCapture(C)) { - // Init captures are always VarDecl. - auto *D = cast(C->getCapturedVar()); + VarDecl *D = C->getCapturedVar(); llvm::StringRef Pre; llvm::StringRef Post; diff --git a/clang/lib/Analysis/AnalysisDeclContext.cpp b/clang/lib/Analysis/AnalysisDeclContext.cpp index f72c75a..f209246 100644 --- a/clang/lib/Analysis/AnalysisDeclContext.cpp +++ b/clang/lib/Analysis/AnalysisDeclContext.cpp @@ -142,7 +142,7 @@ bool AnalysisDeclContext::isBodyAutosynthesizedFromModelFile() const { /// Returns true if \param VD is an Objective-C implicit 'self' parameter. static bool isSelfDecl(const VarDecl *VD) { - return isa_and_nonnull(VD) && VD->getName() == "self"; + return isa(VD) && VD->getName() == "self"; } const ImplicitParamDecl *AnalysisDeclContext::getSelfDecl() const { @@ -169,8 +169,8 @@ const ImplicitParamDecl *AnalysisDeclContext::getSelfDecl() const { if (!LC.capturesVariable()) continue; - ValueDecl *VD = LC.getCapturedVar(); - if (isSelfDecl(dyn_cast(VD))) + VarDecl *VD = LC.getCapturedVar(); + if (isSelfDecl(VD)) return dyn_cast(VD); } diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp index 6527d87..522ed7a 100644 --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -1497,7 +1497,7 @@ void CGDebugInfo::CollectRecordLambdaFields( if (C.capturesVariable()) { SourceLocation Loc = C.getLocation(); assert(!Field->isBitField() && "lambdas don't have bitfield members!"); - ValueDecl *V = C.getCapturedVar(); + VarDecl *V = C.getCapturedVar(); StringRef VName = V->getName(); llvm::DIFile *VUnit = getOrCreateFile(Loc); auto Align = getDeclAlignIfRequired(V, CGM.getContext()); diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index e26822e..91a6b4e 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -2942,13 +2942,8 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) { // FIXME: While we're emitting a binding from an enclosing scope, all other // DeclRefExprs we see should be implicitly treated as if they also refer to // an enclosing scope. - if (const auto *BD = dyn_cast(ND)) { - if (E->refersToEnclosingVariableOrCapture()) { - auto *FD = LambdaCaptureFields.lookup(BD); - return EmitCapturedFieldLValue(*this, FD, CXXABIThisValue); - } + if (const auto *BD = dyn_cast(ND)) return EmitLValue(BD->getBinding()); - } // We can form DeclRefExprs naming GUID declarations when reconstituting // non-type template parameters into expressions. diff --git a/clang/lib/CodeGen/CGOpenMPRuntime.cpp b/clang/lib/CodeGen/CGOpenMPRuntime.cpp index 9fc7360..3a1ed38 100644 --- a/clang/lib/CodeGen/CGOpenMPRuntime.cpp +++ b/clang/lib/CodeGen/CGOpenMPRuntime.cpp @@ -409,7 +409,7 @@ private: /// RAII for emitting code of OpenMP constructs. class InlinedOpenMPRegionRAII { CodeGenFunction &CGF; - llvm::DenseMap LambdaCaptureFields; + llvm::DenseMap LambdaCaptureFields; FieldDecl *LambdaThisCaptureField = nullptr; const CodeGen::CGBlockInfo *BlockInfo = nullptr; bool NoInheritance = false; @@ -8948,7 +8948,7 @@ public: Address VDAddr(Arg, CGF.ConvertTypeForMem(VDType), CGF.getContext().getDeclAlign(VD)); LValue VDLVal = CGF.MakeAddrLValue(VDAddr, VDType); - llvm::DenseMap Captures; + llvm::DenseMap Captures; FieldDecl *ThisCapture = nullptr; RD->getCaptureFields(Captures, ThisCapture); if (ThisCapture) { @@ -8970,7 +8970,7 @@ public: for (const LambdaCapture &LC : RD->captures()) { if (!LC.capturesVariable()) continue; - const VarDecl *VD = cast(LC.getCapturedVar()); + const VarDecl *VD = LC.getCapturedVar(); if (LC.getCaptureKind() != LCK_ByRef && !VD->getType()->isPointerType()) continue; auto It = Captures.find(VD); diff --git a/clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp b/clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp index e8affaa..058b312 100644 --- a/clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp +++ b/clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp @@ -444,8 +444,9 @@ public: markAsEscaped(VD); if (isa(VD)) VisitValueDecl(VD); - else if (VD->isInitCapture()) - VisitValueDecl(VD); + else if (const auto *VarD = dyn_cast(VD)) + if (VarD->isInitCapture()) + VisitValueDecl(VD); } void VisitUnaryOperator(const UnaryOperator *E) { if (!E) @@ -3809,7 +3810,7 @@ void CGOpenMPRuntimeGPU::adjustTargetSpecificDataForLambdas( else VDLVal = CGF.MakeAddrLValue( VDAddr, VD->getType().getCanonicalType().getNonReferenceType()); - llvm::DenseMap Captures; + llvm::DenseMap Captures; FieldDecl *ThisCapture = nullptr; RD->getCaptureFields(Captures, ThisCapture); if (ThisCapture && CGF.CapturedStmtInfo->isCXXThisExprCaptured()) { @@ -3821,15 +3822,13 @@ void CGOpenMPRuntimeGPU::adjustTargetSpecificDataForLambdas( for (const LambdaCapture &LC : RD->captures()) { if (LC.getCaptureKind() != LCK_ByRef) continue; - const ValueDecl *VD = LC.getCapturedVar(); - // FIXME: For now VD is always a VarDecl because OpenMP does not support - // capturing structured bindings in lambdas yet. - if (!CS->capturesVariable(cast(VD))) + const VarDecl *VD = LC.getCapturedVar(); + if (!CS->capturesVariable(VD)) continue; auto It = Captures.find(VD); assert(It != Captures.end() && "Found lambda capture without field."); LValue VarLVal = CGF.EmitLValueForFieldInitialization(VDLVal, It->second); - Address VDAddr = CGF.GetAddrOfLocalVar(cast(VD)); + Address VDAddr = CGF.GetAddrOfLocalVar(VD); if (VD->getType().getCanonicalType()->isReferenceType()) VDAddr = CGF.EmitLoadOfReferenceLValue(VDAddr, VD->getType().getCanonicalType()) diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index b61a2a6..fe0890f 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -609,7 +609,7 @@ public: const CodeGen::CGBlockInfo *BlockInfo = nullptr; llvm::Value *BlockPointer = nullptr; - llvm::DenseMap LambdaCaptureFields; + llvm::DenseMap LambdaCaptureFields; FieldDecl *LambdaThisCaptureField = nullptr; /// A mapping from NRVO variables to the flags used to indicate diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index b110a07..eca2000 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -14681,7 +14681,7 @@ static void RebuildLambdaScopeInfo(CXXMethodDecl *CallOperator, auto I = LambdaClass->field_begin(); for (const auto &C : LambdaClass->captures()) { if (C.capturesVariable()) { - ValueDecl *VD = C.getCapturedVar(); + VarDecl *VD = C.getCapturedVar(); if (VD->isInitCapture()) S.CurrentInstantiationScope->InstantiatedLocal(VD, VD); const bool ByRef = C.getCaptureKind() == LCK_ByRef; diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 3cadd02..6f758e4 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -2082,8 +2082,9 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK, NestedNameSpecifierLoc NNS, NamedDecl *FoundD, SourceLocation TemplateKWLoc, const TemplateArgumentListInfo *TemplateArgs) { - bool RefersToCapturedVariable = isa(D) && - NeedToCaptureVariable(D, NameInfo.getLoc()); + bool RefersToCapturedVariable = + isa(D) && + NeedToCaptureVariable(cast(D), NameInfo.getLoc()); DeclRefExpr *E = DeclRefExpr::Create( Context, NNS, TemplateKWLoc, D, RefersToCapturedVariable, NameInfo, Ty, @@ -3251,9 +3252,8 @@ ExprResult Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS, return ULE; } -static void diagnoseUncapturableValueReferenceOrBinding(Sema &S, - SourceLocation loc, - ValueDecl *var); +static void diagnoseUncapturableValueReference(Sema &S, SourceLocation loc, + ValueDecl *var); /// Complete semantic analysis for a reference to the given declaration. ExprResult Sema::BuildDeclarationNameExpr( @@ -3411,11 +3411,20 @@ ExprResult Sema::BuildDeclarationNameExpr( break; } - case Decl::Binding: + case Decl::Binding: { // These are always lvalues. valueKind = VK_LValue; type = type.getNonReferenceType(); + // FIXME: Support lambda-capture of BindingDecls, once CWG actually + // decides how that's supposed to work. + auto *BD = cast(VD); + if (BD->getDeclContext() != CurContext) { + auto *DD = dyn_cast_or_null(BD->getDecomposedDecl()); + if (DD && DD->hasLocalStorage()) + diagnoseUncapturableValueReference(*this, Loc, BD); + } break; + } case Decl::Function: { if (unsigned BID = cast(VD)->getBuiltinID()) { @@ -16402,9 +16411,8 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc, for (Capture &Cap : BSI->Captures) { if (Cap.isInvalid() || Cap.isThisCapture()) continue; - // Cap.getVariable() is always a VarDecl because - // blocks cannot capture structured bindings or other ValueDecl kinds. - auto *Var = cast(Cap.getVariable()); + + VarDecl *Var = Cap.getVariable(); Expr *CopyExpr = nullptr; if (getLangOpts().CPlusPlus && Cap.isCopyCapture()) { if (const RecordType *Record = @@ -18235,8 +18243,8 @@ void Sema::MarkCaptureUsedInEnclosingContext(VarDecl *Capture, MarkVarDeclODRUsed(Capture, Loc, *this, &CapturingScopeIndex); } -void diagnoseUncapturableValueReferenceOrBinding(Sema &S, SourceLocation loc, - ValueDecl *var) { +static void diagnoseUncapturableValueReference(Sema &S, SourceLocation loc, + ValueDecl *var) { DeclContext *VarDC = var->getDeclContext(); // If the parameter still belongs to the translation unit, then @@ -18276,12 +18284,12 @@ void diagnoseUncapturableValueReferenceOrBinding(Sema &S, SourceLocation loc, // capture. } -static bool isVariableAlreadyCapturedInScopeInfo(CapturingScopeInfo *CSI, - ValueDecl *Var, - bool &SubCapturesAreNested, - QualType &CaptureType, - QualType &DeclRefType) { - // Check whether we've already captured it. + +static bool isVariableAlreadyCapturedInScopeInfo(CapturingScopeInfo *CSI, VarDecl *Var, + bool &SubCapturesAreNested, + QualType &CaptureType, + QualType &DeclRefType) { + // Check whether we've already captured it. if (CSI->CaptureMap.count(Var)) { // If we found a capture, any subcaptures are nested. SubCapturesAreNested = true; @@ -18308,22 +18316,14 @@ static bool isVariableAlreadyCapturedInScopeInfo(CapturingScopeInfo *CSI, // Only block literals, captured statements, and lambda expressions can // capture; other scopes don't work. -static DeclContext *getParentOfCapturingContextOrNull(DeclContext *DC, - ValueDecl *Var, - SourceLocation Loc, - const bool Diagnose, - Sema &S) { +static DeclContext *getParentOfCapturingContextOrNull(DeclContext *DC, VarDecl *Var, + SourceLocation Loc, + const bool Diagnose, Sema &S) { if (isa(DC) || isa(DC) || isLambdaCallOperator(DC)) return getLambdaAwareParentOfDeclContext(DC); - - ValueDecl *Underlying = Var; - auto *BD = dyn_cast_or_null(Var); - if (BD) - Underlying = BD->getDecomposedDecl(); - - if (auto *VD = dyn_cast(Underlying)) { - if (VD->hasLocalStorage() && Diagnose) - diagnoseUncapturableValueReferenceOrBinding(S, Loc, Var); + else if (Var->hasLocalStorage()) { + if (Diagnose) + diagnoseUncapturableValueReference(S, Loc, Var); } return nullptr; } @@ -18331,12 +18331,9 @@ static DeclContext *getParentOfCapturingContextOrNull(DeclContext *DC, // Certain capturing entities (lambdas, blocks etc.) are not allowed to capture // certain types of variables (unnamed, variably modified types etc.) // so check for eligibility. -static bool isVariableCapturable(CapturingScopeInfo *CSI, ValueDecl *Var, - SourceLocation Loc, const bool Diagnose, - Sema &S) { - - assert((isa(Var)) && - "Only variables and structured bindings can be captured"); +static bool isVariableCapturable(CapturingScopeInfo *CSI, VarDecl *Var, + SourceLocation Loc, + const bool Diagnose, Sema &S) { bool IsBlock = isa(CSI); bool IsLambda = isa(CSI); @@ -18393,28 +18390,17 @@ static bool isVariableCapturable(CapturingScopeInfo *CSI, ValueDecl *Var, return false; } - if (isa(Var)) { - if (!IsLambda || !S.getLangOpts().CPlusPlus) { - if (Diagnose) - diagnoseUncapturableValueReferenceOrBinding(S, Loc, Var); - return false; - } else if (Diagnose && S.getLangOpts().CPlusPlus) { - S.Diag(Loc, S.LangOpts.CPlusPlus20 - ? diag::warn_cxx17_compat_capture_binding - : diag::ext_capture_binding) - << Var; - S.Diag(Var->getLocation(), diag::note_entity_declared_at) << Var; - } - } - return true; } // Returns true if the capture by block was successful. -static bool captureInBlock(BlockScopeInfo *BSI, ValueDecl *Var, - SourceLocation Loc, const bool BuildAndDiagnose, - QualType &CaptureType, QualType &DeclRefType, - const bool Nested, Sema &S, bool Invalid) { +static bool captureInBlock(BlockScopeInfo *BSI, VarDecl *Var, + SourceLocation Loc, + const bool BuildAndDiagnose, + QualType &CaptureType, + QualType &DeclRefType, + const bool Nested, + Sema &S, bool Invalid) { bool ByRef = false; // Blocks are not allowed to capture arrays, excepting OpenCL. @@ -18478,9 +18464,10 @@ static bool captureInBlock(BlockScopeInfo *BSI, ValueDecl *Var, return !Invalid; } + /// Capture the given variable in the captured region. static bool captureInCapturedRegion( - CapturedRegionScopeInfo *RSI, ValueDecl *Var, SourceLocation Loc, + CapturedRegionScopeInfo *RSI, VarDecl *Var, SourceLocation Loc, const bool BuildAndDiagnose, QualType &CaptureType, QualType &DeclRefType, const bool RefersToCapturedVariable, Sema::TryCaptureKind Kind, bool IsTopScope, Sema &S, bool Invalid) { @@ -18519,12 +18506,16 @@ static bool captureInCapturedRegion( } /// Capture the given variable in the lambda. -static bool captureInLambda(LambdaScopeInfo *LSI, ValueDecl *Var, - SourceLocation Loc, const bool BuildAndDiagnose, - QualType &CaptureType, QualType &DeclRefType, +static bool captureInLambda(LambdaScopeInfo *LSI, + VarDecl *Var, + SourceLocation Loc, + const bool BuildAndDiagnose, + QualType &CaptureType, + QualType &DeclRefType, const bool RefersToCapturedVariable, const Sema::TryCaptureKind Kind, - SourceLocation EllipsisLoc, const bool IsTopScope, + SourceLocation EllipsisLoc, + const bool IsTopScope, Sema &S, bool Invalid) { // Determine whether we are capturing by reference or by value. bool ByRef = false; @@ -18533,42 +18524,6 @@ static bool captureInLambda(LambdaScopeInfo *LSI, ValueDecl *Var, } else { ByRef = (LSI->ImpCaptureStyle == LambdaScopeInfo::ImpCap_LambdaByref); } - // C++20 : [expr.prim.lambda.capture]p12 - // A bit-field or a member of an anonymous union shall - // not be captured by reference. - MemberExpr *ME = nullptr; - BindingDecl *BD = nullptr; - if (auto *V = dyn_cast(Var)) { - if (V->getInit()) - ME = dyn_cast(V->getInit()->IgnoreImplicit()); - } else if ((BD = dyn_cast(Var))) { - ME = dyn_cast_or_null(BD->getBinding()); - } - - // Capturing a bitfield by reference is not allowed except in OpenMP. - if (ByRef && ME && - (isa(Var) || !S.LangOpts.OpenMP || - !S.isOpenMPCapturedDecl(Var))) { - const auto *FD = dyn_cast_or_null(ME->getMemberDecl()); - if (FD && - (FD->isBitField() || (FD->getParent()->isAnonymousStructOrUnion() && - FD->getParent()->isUnion()))) { - if (BuildAndDiagnose) { - S.Diag(Loc, diag::err_bitfield_capture_by_ref) << Var; - S.Diag(Var->getLocation(), diag::note_entity_declared_at) << Var; - S.Diag(FD->getLocation(), diag::note_bitfield_decl) << FD; - } - Invalid = true; - } - } - // FIXME: We should support capturing structured bindings in OpenMP. - if (!Invalid && BD && S.LangOpts.OpenMP) { - if (BuildAndDiagnose) { - S.Diag(Loc, diag::err_capture_binding_openmp) << Var; - S.Diag(Var->getLocation(), diag::note_entity_declared_at) << Var; - } - Invalid = true; - } // Compute the type of the field that will capture this variable. if (ByRef) { @@ -18650,8 +18605,7 @@ static bool captureInLambda(LambdaScopeInfo *LSI, ValueDecl *Var, return !Invalid; } -static bool canCaptureVariableByCopy(ValueDecl *Var, - const ASTContext &Context) { +static bool canCaptureVariableByCopy(VarDecl *Var, const ASTContext &Context) { // Offer a Copy fix even if the type is dependent. if (Var->getType()->isDependentType()) return true; @@ -18677,7 +18631,7 @@ static bool canCaptureVariableByCopy(ValueDecl *Var, /// standard, for example we can't emit a default copy capture fix-it if we /// already explicitly copy capture capture another variable. static void buildLambdaCaptureFixit(Sema &Sema, LambdaScopeInfo *LSI, - ValueDecl *Var) { + VarDecl *Var) { assert(LSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_None); // Don't offer Capture by copy of default capture by copy fixes if Var is // known not to be copy constructible. @@ -18753,21 +18707,14 @@ static void buildLambdaCaptureFixit(Sema &Sema, LambdaScopeInfo *LSI, } bool Sema::tryCaptureVariable( - ValueDecl *Var, SourceLocation ExprLoc, TryCaptureKind Kind, + VarDecl *Var, SourceLocation ExprLoc, TryCaptureKind Kind, SourceLocation EllipsisLoc, bool BuildAndDiagnose, QualType &CaptureType, QualType &DeclRefType, const unsigned *const FunctionScopeIndexToStopAt) { // An init-capture is notionally from the context surrounding its // declaration, but its parent DC is the lambda class. DeclContext *VarDC = Var->getDeclContext(); - const auto *VD = dyn_cast(Var); - if (VD) { - if (VD->isInitCapture()) - VarDC = VarDC->getParent(); - } else { - VD = dyn_cast( - cast(Var)->getDecomposedDecl()); - } - assert(VD && "Cannot capture a null variable"); + if (Var->isInitCapture()) + VarDC = VarDC->getParent(); DeclContext *DC = CurContext; const unsigned MaxFunctionScopesIndex = FunctionScopeIndexToStopAt @@ -18789,14 +18736,12 @@ bool Sema::tryCaptureVariable( // Capture global variables if it is required to use private copy of this // variable. - bool IsGlobal = !VD->hasLocalStorage(); + bool IsGlobal = !Var->hasLocalStorage(); if (IsGlobal && !(LangOpts.OpenMP && isOpenMPCapturedDecl(Var, /*CheckScopeInfo=*/true, MaxFunctionScopesIndex))) return true; - - if (isa(Var)) - Var = cast(Var->getCanonicalDecl()); + Var = Var->getCanonicalDecl(); // Walk up the stack to determine whether we can capture the variable, // performing the "simple" checks that don't depend on type. We stop when @@ -18852,7 +18797,7 @@ bool Sema::tryCaptureVariable( Diag(LSI->Lambda->getBeginLoc(), diag::note_lambda_decl); buildLambdaCaptureFixit(*this, LSI, Var); } else - diagnoseUncapturableValueReferenceOrBinding(*this, ExprLoc, Var); + diagnoseUncapturableValueReference(*this, ExprLoc, Var); } return true; } @@ -19000,7 +18945,7 @@ bool Sema::tryCaptureVariable( return Invalid; } -bool Sema::tryCaptureVariable(ValueDecl *Var, SourceLocation Loc, +bool Sema::tryCaptureVariable(VarDecl *Var, SourceLocation Loc, TryCaptureKind Kind, SourceLocation EllipsisLoc) { QualType CaptureType; QualType DeclRefType; @@ -19009,7 +18954,7 @@ bool Sema::tryCaptureVariable(ValueDecl *Var, SourceLocation Loc, DeclRefType, nullptr); } -bool Sema::NeedToCaptureVariable(ValueDecl *Var, SourceLocation Loc) { +bool Sema::NeedToCaptureVariable(VarDecl *Var, SourceLocation Loc) { QualType CaptureType; QualType DeclRefType; return !tryCaptureVariable(Var, Loc, TryCapture_Implicit, SourceLocation(), @@ -19017,7 +18962,7 @@ bool Sema::NeedToCaptureVariable(ValueDecl *Var, SourceLocation Loc) { DeclRefType, nullptr); } -QualType Sema::getCapturedDeclRefType(ValueDecl *Var, SourceLocation Loc) { +QualType Sema::getCapturedDeclRefType(VarDecl *Var, SourceLocation Loc) { QualType CaptureType; QualType DeclRefType; @@ -19613,24 +19558,6 @@ static void DoMarkVarDeclReferenced( } } -static void DoMarkBindingDeclReferenced(Sema &SemaRef, SourceLocation Loc, - BindingDecl *BD) { - BD->setReferenced(); - - if (BD->isInvalidDecl()) - return; - - OdrUseContext OdrUse = isOdrUseContext(SemaRef); - if (OdrUse == OdrUseContext::Used) { - QualType CaptureType, DeclRefType; - SemaRef.tryCaptureVariable(BD, Loc, Sema::TryCapture_Implicit, - /*EllipsisLoc*/ SourceLocation(), - /*BuildAndDiagnose*/ true, CaptureType, - DeclRefType, - /*FunctionScopeIndexToStopAt*/ nullptr); - } -} - /// Mark a variable referenced, and check whether it is odr-used /// (C++ [basic.def.odr]p2, C99 6.9p3). Note that this should not be /// used directly for normal expressions referring to VarDecl. @@ -19650,11 +19577,6 @@ MarkExprReferenced(Sema &SemaRef, SourceLocation Loc, Decl *D, Expr *E, return; } - if (BindingDecl *Decl = dyn_cast(D)) { - DoMarkBindingDeclReferenced(SemaRef, Loc, Decl); - return; - } - SemaRef.MarkAnyDeclReferenced(Loc, D, MightBeOdrUse); // If this is a call to a method via a cast, also mark the method in the diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index 737952b..d3b4548 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -7846,7 +7846,7 @@ void Sema::checkInitializerLifetime(const InitializedEntity &Entity, break; // FIXME: We can't easily tell apart an init-capture from a nested // capture of an init-capture. - const ValueDecl *VD = Elem.Capture->getCapturedVar(); + const VarDecl *VD = Elem.Capture->getCapturedVar(); Diag(Elem.Capture->getLocation(), diag::note_lambda_capture_initializer) << VD << VD->isInitCapture() << Elem.Capture->isExplicit() << (Elem.Capture->getCaptureKind() == LCK_ByRef) << VD diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp index 3f271d6..afc2f3e 100644 --- a/clang/lib/Sema/SemaLambda.cpp +++ b/clang/lib/Sema/SemaLambda.cpp @@ -1088,7 +1088,7 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, if (C->Init.isInvalid()) continue; - ValueDecl *Var = nullptr; + VarDecl *Var = nullptr; if (C->Init.isUsable()) { Diag(C->Loc, getLangOpts().CPlusPlus14 ? diag::warn_cxx11_compat_init_capture @@ -1166,10 +1166,7 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, continue; } - if (auto *BD = R.getAsSingle()) - Var = BD; - else - Var = R.getAsSingle(); + Var = R.getAsSingle(); if (Var && DiagnoseUseOfDecl(Var, C->Loc)) continue; } @@ -1203,13 +1200,7 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, if (Var->isInvalidDecl()) continue; - VarDecl *Underlying; - if (auto *BD = dyn_cast(Var)) - Underlying = dyn_cast(BD->getDecomposedDecl()); - else - Underlying = cast(Var); - - if (!Underlying->hasLocalStorage()) { + if (!Var->hasLocalStorage()) { Diag(C->Loc, diag::err_capture_non_automatic_variable) << C->Id; Diag(Var->getLocation(), diag::note_previous_decl) << C->Id; continue; @@ -1233,7 +1224,7 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, } if (C->Init.isUsable()) { - addInitCapture(LSI, cast(Var)); + addInitCapture(LSI, Var); } else { TryCaptureKind Kind = C->Kind == LCK_ByRef ? TryCapture_ExplicitByRef : TryCapture_ExplicitByVal; @@ -1583,7 +1574,7 @@ ExprResult Sema::BuildCaptureInit(const Capture &Cap, // An init-capture is initialized directly from its stored initializer. if (Cap.isInitCapture()) - return cast(Cap.getVariable())->getInit(); + return Cap.getVariable()->getInit(); // For anything else, build an initialization expression. For an implicit // capture, the capture notionally happens at the capture-default, so use @@ -1614,7 +1605,7 @@ ExprResult Sema::BuildCaptureInit(const Capture &Cap, Init = This; } else { assert(Cap.isVariableCapture() && "unknown kind of capture"); - ValueDecl *Var = Cap.getVariable(); + VarDecl *Var = Cap.getVariable(); Name = Var->getIdentifier(); Init = BuildDeclarationNameExpr( CXXScopeSpec(), DeclarationNameInfo(Var->getDeclName(), Loc), Var); @@ -1663,7 +1654,7 @@ mapImplicitCaptureStyle(CapturingScopeInfo::ImplicitCaptureStyle ICS) { bool Sema::CaptureHasSideEffects(const Capture &From) { if (From.isInitCapture()) { - Expr *Init = cast(From.getVariable())->getInit(); + Expr *Init = From.getVariable()->getInit(); if (Init && Init->HasSideEffects(Context)) return true; } @@ -1713,9 +1704,9 @@ FieldDecl *Sema::BuildCaptureField(RecordDecl *RD, TypeSourceInfo *TSI = nullptr; if (Capture.isVariableCapture()) { - const auto *Var = dyn_cast_or_null(Capture.getVariable()); - if (Var && Var->isInitCapture()) - TSI = Var->getTypeSourceInfo(); + auto *Var = Capture.getVariable(); + if (Var->isInitCapture()) + TSI = Capture.getVariable()->getTypeSourceInfo(); } // FIXME: Should we really be doing this? A null TypeSourceInfo seems more @@ -1863,7 +1854,7 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc, return LambdaCapture(From.getLocation(), IsImplicit, LCK_VLAType); } else { assert(From.isVariableCapture() && "unknown kind of capture"); - ValueDecl *Var = From.getVariable(); + VarDecl *Var = From.getVariable(); LambdaCaptureKind Kind = From.isCopyCapture() ? LCK_ByCopy : LCK_ByRef; return LambdaCapture(From.getLocation(), IsImplicit, Kind, Var, diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp index 4279a15..a92fec6 100644 --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -4677,12 +4677,12 @@ void Sema::tryCaptureOpenMPLambdas(ValueDecl *V) { DSAStack->setForceCaptureByReferenceInTargetExecutable( /*V=*/true); if (RD->isLambda()) { - llvm::DenseMap Captures; + llvm::DenseMap Captures; FieldDecl *ThisCapture; RD->getCaptureFields(Captures, ThisCapture); for (const LambdaCapture &LC : RD->captures()) { if (LC.getCaptureKind() == LCK_ByRef) { - VarDecl *VD = cast(LC.getCapturedVar()); + VarDecl *VD = LC.getCapturedVar(); DeclContext *VDC = VD->getDeclContext(); if (!VDC->Encloses(CurContext)) continue; diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp index 73d243c..c6ca10c 100644 --- a/clang/lib/Sema/SemaStmt.cpp +++ b/clang/lib/Sema/SemaStmt.cpp @@ -4695,11 +4695,11 @@ buildCapturedStmtCaptureList(Sema &S, CapturedRegionScopeInfo *RSI, if (S.getLangOpts().OpenMP && RSI->CapRegionKind == CR_OpenMP) S.setOpenMPCaptureKind(Field, Cap.getVariable(), RSI->OpenMPLevel); - Captures.push_back(CapturedStmt::Capture( - Cap.getLocation(), - Cap.isReferenceCapture() ? CapturedStmt::VCK_ByRef - : CapturedStmt::VCK_ByCopy, - cast(Cap.getVariable()))); + Captures.push_back(CapturedStmt::Capture(Cap.getLocation(), + Cap.isReferenceCapture() + ? CapturedStmt::VCK_ByRef + : CapturedStmt::VCK_ByCopy, + Cap.getVariable())); } CaptureInits.push_back(Init.get()); } diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 14f6526..86d9215 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -12986,7 +12986,7 @@ TreeTransform::TransformLambdaExpr(LambdaExpr *E) { continue; TransformedInitCapture &Result = InitCaptures[C - E->capture_begin()]; - auto *OldVD = cast(C->getCapturedVar()); + VarDecl *OldVD = C->getCapturedVar(); auto SubstInitCapture = [&](SourceLocation EllipsisLoc, Optional NumExpansions) { @@ -13003,8 +13003,7 @@ TreeTransform::TransformLambdaExpr(LambdaExpr *E) { getSema().buildLambdaInitCaptureInitialization( C->getLocation(), OldVD->getType()->isReferenceType(), EllipsisLoc, NumExpansions, OldVD->getIdentifier(), - cast(C->getCapturedVar())->getInitStyle() != - VarDecl::CInit, + C->getCapturedVar()->getInitStyle() != VarDecl::CInit, NewExprInit); Result.Expansions.push_back( InitCaptureInfoTy(NewExprInit, NewInitCaptureType)); @@ -13171,7 +13170,7 @@ TreeTransform::TransformLambdaExpr(LambdaExpr *E) { if (E->isInitCapture(C)) { TransformedInitCapture &NewC = InitCaptures[C - E->capture_begin()]; - auto *OldVD = cast(C->getCapturedVar()); + VarDecl *OldVD = C->getCapturedVar(); llvm::SmallVector NewVDs; for (InitCaptureInfoTy &Info : NewC.Expansions) { @@ -13226,7 +13225,7 @@ TreeTransform::TransformLambdaExpr(LambdaExpr *E) { // The transform has determined that we should perform an expansion; // transform and capture each of the arguments. // expansion of the pattern. Do so. - auto *Pack = cast(C->getCapturedVar()); + VarDecl *Pack = C->getCapturedVar(); for (unsigned I = 0; I != *NumExpansions; ++I) { Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), I); VarDecl *CapturedVar diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index 7e0496f..34af5d6 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -5786,7 +5786,7 @@ void ASTRecordWriter::AddCXXDefinitionData(const CXXRecordDecl *D) { break; case LCK_ByCopy: case LCK_ByRef: - ValueDecl *Var = + VarDecl *Var = Capture.capturesVariable() ? Capture.getCapturedVar() : nullptr; AddDeclRef(Var); AddSourceLocation(Capture.isPackExpansion() ? Capture.getEllipsisLoc() diff --git a/clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp index 8b6304f..2102f92 100644 --- a/clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp @@ -504,7 +504,7 @@ public: // Treat local variables captured by reference in C++ lambdas as escaped. void findLambdaReferenceCaptures(const LambdaExpr *LE) { const CXXRecordDecl *LambdaClass = LE->getLambdaClass(); - llvm::DenseMap CaptureFields; + llvm::DenseMap CaptureFields; FieldDecl *ThisCaptureField; LambdaClass->getCaptureFields(CaptureFields, ThisCaptureField); @@ -512,14 +512,14 @@ public: if (!C.capturesVariable()) continue; - ValueDecl *VD = C.getCapturedVar(); + VarDecl *VD = C.getCapturedVar(); const FieldDecl *FD = CaptureFields[VD]; - if (!FD || !isa(VD)) + if (!FD) continue; // If the capture field is a reference type, it is capture-by-reference. if (FD->getType()->isReferenceType()) - Escaped.insert(cast(VD)); + Escaped.insert(VD); } } }; diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedLambdaCapturesChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedLambdaCapturesChecker.cpp index 0c952b5..deebbd6 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedLambdaCapturesChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedLambdaCapturesChecker.cpp @@ -57,7 +57,7 @@ public: void visitLambdaExpr(LambdaExpr *L) const { for (const LambdaCapture &C : L->captures()) { if (C.capturesVariable()) { - ValueDecl *CapturedVar = C.getCapturedVar(); + VarDecl *CapturedVar = C.getCapturedVar(); if (auto *CapturedVarType = CapturedVar->getType().getTypePtrOrNull()) { Optional IsUncountedPtr = isUncountedPtr(CapturedVarType); if (IsUncountedPtr && *IsUncountedPtr) { @@ -68,7 +68,7 @@ public: } } - void reportBug(const LambdaCapture &Capture, ValueDecl *CapturedVar, + void reportBug(const LambdaCapture &Capture, VarDecl *CapturedVar, const Type *T) const { assert(CapturedVar); diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp index 049b7d4..cdd5660 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -2732,7 +2732,7 @@ void ExprEngine::VisitCommonDeclRefExpr(const Expr *Ex, const NamedDecl *D, MD->getParent()->isLambda()) { // Lookup the field of the lambda. const CXXRecordDecl *CXXRec = MD->getParent(); - llvm::DenseMap LambdaCaptureFields; + llvm::DenseMap LambdaCaptureFields; FieldDecl *LambdaThisCaptureField; CXXRec->getCaptureFields(LambdaCaptureFields, LambdaThisCaptureField); diff --git a/clang/lib/StaticAnalyzer/Core/LoopUnrolling.cpp b/clang/lib/StaticAnalyzer/Core/LoopUnrolling.cpp index f6efde8..506d61d 100644 --- a/clang/lib/StaticAnalyzer/Core/LoopUnrolling.cpp +++ b/clang/lib/StaticAnalyzer/Core/LoopUnrolling.cpp @@ -175,7 +175,7 @@ static bool isCapturedByReference(ExplodedNode *N, const DeclRefExpr *DR) { const CXXRecordDecl *LambdaCXXRec = MD->getParent(); // Lookup the fields of the lambda - llvm::DenseMap LambdaCaptureFields; + llvm::DenseMap LambdaCaptureFields; FieldDecl *LambdaThisCaptureField; LambdaCXXRec->getCaptureFields(LambdaCaptureFields, LambdaThisCaptureField); diff --git a/clang/test/CodeGenCXX/cxx20-decomposition.cpp b/clang/test/CodeGenCXX/cxx20-decomposition.cpp deleted file mode 100644 index 1654503..0000000 --- a/clang/test/CodeGenCXX/cxx20-decomposition.cpp +++ /dev/null @@ -1,48 +0,0 @@ -// RUN: %clang_cc1 -std=c++20 -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck %s - -struct S { - int i; - int j; -}; - -int f() { - auto [i, j] = S{1, 42}; - return [&i, j] { - return i + j; - }(); -} - -// Ensures the representation of the lambda, the order of the -// 1st 2nd don't matter except for ABI-esque things, but make sure -// that the ref-capture is a ptr, and 'j' is captured by value. -// CHECK: %[[LAMBDA_TY:.+]] = type <{ ptr, i32, [4 x i8] }> - -// Check the captures themselves. -// CHECK: define{{.*}} i32 @_Z1fv() -// CHECK: %[[BINDING:.+]] = alloca %struct.S -// CHECK: %[[LAMBDA:.+]] = alloca %[[LAMBDA_TY]] - -// Copy a pointer to the binding, for reference capture. -// CHECK: %[[LAMBDA_CAP_PTR:.+]] = getelementptr inbounds %[[LAMBDA_TY]], ptr %[[LAMBDA]], i32 0, i32 0 -// CHECK: %[[BINDING_PTR:.+]] = getelementptr inbounds %struct.S, ptr %[[BINDING]], i32 0, i32 0 -// CHECK: store ptr %[[BINDING_PTR]], ptr %[[LAMBDA_CAP_PTR]] - -// Copy the integer from the binding, for copy capture. -// CHECK: %[[LAMBDA_CAP_INT:.+]] = getelementptr inbounds %[[LAMBDA_TY]], ptr %[[LAMBDA]], i32 0, i32 1 -// CHECK: %[[PTR_TO_J:.+]] = getelementptr inbounds %struct.S, ptr %[[BINDING]], i32 0, i32 1 -// CHECK: %[[J_COPY:.+]] = load i32, ptr %[[PTR_TO_J]] -// CHECK: store i32 %[[J_COPY]], ptr %[[LAMBDA_CAP_INT]] - -// Ensure the captures are properly extracted in operator(). -// CHECK: define{{.*}} i32 @"_ZZ1fvENK3$_0clEv" -// CHECK: %[[THIS_ADDR:.+]] = alloca ptr -// CHECK: %[[THIS_PTR:.+]] = load ptr, ptr %[[THIS_ADDR]] - -// Load 'i', passed by reference. -// CHECK: %[[LAMBDA_GEP_TO_PTR:.+]] = getelementptr inbounds %[[LAMBDA_TY]], ptr %[[THIS_PTR]], i32 0, i32 0 -// CHECK: %[[I_PTR:.+]] = load ptr, ptr %[[LAMBDA_GEP_TO_PTR]] -// CHECK: %[[I_VALUE:.+]] = load i32, ptr %[[I_PTR]] - -// Load the 'j', passed by value. -// CHECK: %[[LAMBDA_GEP_TO_INT:.+]] = getelementptr inbounds %[[LAMBDA_TY]], ptr %[[THIS_PTR]], i32 0, i32 1 -// CHECK: %[[J_VALUE:.+]] = load i32, ptr %[[LAMBDA_GEP_TO_INT]] diff --git a/clang/test/SemaCXX/cxx1z-decomposition.cpp b/clang/test/SemaCXX/cxx1z-decomposition.cpp index 7165f30..4c8c641 100644 --- a/clang/test/SemaCXX/cxx1z-decomposition.cpp +++ b/clang/test/SemaCXX/cxx1z-decomposition.cpp @@ -1,5 +1,4 @@ -// RUN: %clang_cc1 -std=c++17 -Wc++20-extensions -verify=expected %s -// RUN: %clang_cc1 -std=c++20 -Wpre-c++20-compat -verify=expected %s +// RUN: %clang_cc1 -std=c++17 -verify %s void use_from_own_init() { auto [a] = a; // expected-error {{binding 'a' cannot appear in the initializer of its own decomposition declaration}} @@ -47,58 +46,25 @@ constexpr int f(S s) { } static_assert(f({1, 2}) == 12); -constexpr bool g(S &&s) { +constexpr bool g(S &&s) { auto &[a, b] = s; return &a == &s.a && &b == &s.b && &a != &b; } static_assert(g({1, 2})); -struct S1 { - int a, b; -}; -struct S2 { - int a : 1; // expected-note 2{{bit-field is declared here}} - int b; -}; - -auto [outer1, outer2] = S1{1, 2}; -auto [outerbit1, outerbit2] = S1{1, 2}; // expected-note {{declared here}} - +auto [outer1, outer2] = S{1, 2}; void enclosing() { struct S { int a = outer1; }; - auto [n] = S(); // expected-note 3{{'n' declared here}} - - struct Q { - int f() { return n; } // expected-error {{reference to local binding 'n' declared in enclosing function 'enclosing'}} - }; - - (void)[&] { return n; }; // expected-warning {{C++20}} - (void)[n] { return n; }; // expected-warning {{C++20}} + auto [n] = S(); // expected-note 2{{'n' declared here}} - static auto [m] = S(); // expected-note {{'m' declared here}} \ - // expected-warning {{C++20}} + struct Q { int f() { return n; } }; // expected-error {{reference to local binding 'n' declared in enclosing function}} + (void) [&] { return n; }; // expected-error {{reference to local binding 'n' declared in enclosing function}} + (void) [n] {}; // expected-error {{'n' in capture list does not name a variable}} + static auto [m] = S(); // expected-warning {{extension}} struct R { int f() { return m; } }; (void) [&] { return m; }; - (void)[m]{}; // expected-error {{'m' cannot be captured because it does not have automatic storage duration}} - - (void)[outerbit1]{}; // expected-error {{'outerbit1' cannot be captured because it does not have automatic storage duration}} - - auto [bit, var] = S2{1, 1}; // expected-note 4{{'bit' declared here}} - - (void)[&bit] { // expected-error {{cannot capture a bit-field by reference}} \ - // expected-warning {{C++20}} - return bit; - }; - - union { // expected-note {{declared here}} - int u; - }; - - (void)[&] { return bit + u; } // expected-error {{unnamed variable cannot be implicitly captured in a lambda expression}} \ - // expected-error {{cannot capture a bit-field by reference}} \ - // expected-warning {{C++20}} - (); + (void) [m] {}; // expected-error {{'m' in capture list does not name a variable}} } void bitfield() { @@ -132,7 +98,7 @@ template void dependent_foreach(T t) { struct PR37352 { int n; - void f() { static auto [a] = *this; } // expected-warning {{C++20}} + void f() { static auto [a] = *this; } // expected-warning {{C++20 extension}} }; namespace instantiate_template { diff --git a/clang/test/SemaCXX/cxx20-decomposition.cpp b/clang/test/SemaCXX/cxx20-decomposition.cpp deleted file mode 100644 index a99766f5..0000000 --- a/clang/test/SemaCXX/cxx20-decomposition.cpp +++ /dev/null @@ -1,141 +0,0 @@ -// RUN: %clang_cc1 -fsyntax-only -std=c++20 -verify %s -// expected-no-diagnostics - -template -constexpr bool is_same = false; -template -constexpr bool is_same = true; - -struct S { - int i; - int &j; -}; - -void check_category() { - int a = 42; - { - auto [v, r] = S{1, a}; - (void)[ v, r ] { - static_assert(is_same); - static_assert(is_same); - }; - } - { - auto [v, r] = S{1, a}; - (void)[&v, &r ] { - static_assert(is_same); - static_assert(is_same); - }; - } - { - S s{1, a}; - const auto &[v, r] = s; - (void)[ v, r ] { - static_assert(is_same); - static_assert(is_same); - }; - } - { - S s{1, a}; - const auto &[v, r] = s; - (void)[&v, &r ] { - static_assert(is_same); - static_assert(is_same); - }; - } -} - -void check_array() { - int arr[2] = {42, 42}; - auto &[a, b] = arr; - (void)[ a, &b ] { - static_assert(is_same); - static_assert(is_same); - }; -} - -struct tuple { - template - decltype(auto) get() { - if constexpr (I == 0) { - return a; - } else { - return b; - } - } - - template - decltype(auto) get() const { - if constexpr (I == 0) { - return a; - } else { - return b; - } - } - - int a = 0; - int &b = a; -}; - -namespace std { - -template -struct tuple_size { - static constexpr unsigned long value = 2; -}; - -template -struct tuple_element; - -template <> -struct tuple_element<0, tuple> { - using type = int; -}; - -template <> -struct tuple_element<1, tuple> { - using type = int &; -}; - -template <> -struct tuple_element<0, const tuple> { - using type = int; -}; - -template <> -struct tuple_element<1, const tuple> { - using type = const int &; -}; -} // namespace std - -void check_tuple_like() { - tuple t; - { - auto [v, r] = t; - (void)[ v, r ] { - static_assert(is_same); - static_assert(is_same); - }; - } - { - auto &[v, r] = t; - (void)[&v, &r ] { - static_assert(is_same); - static_assert(is_same); - }; - } - { - const auto &[v, r] = t; - (void)[ v, r ] { - static_assert(is_same); - static_assert(is_same); - }; - } - { - const auto &[v, r] = t; - (void)[&v, &r ] { - static_assert(is_same); - static_assert(is_same); - }; - } -} diff --git a/clang/test/SemaCXX/decomposition-blocks.cpp b/clang/test/SemaCXX/decomposition-blocks.cpp deleted file mode 100644 index 21f66f8..0000000 --- a/clang/test/SemaCXX/decomposition-blocks.cpp +++ /dev/null @@ -1,14 +0,0 @@ -// RUN: %clang_cc1 -std=c++17 -fsyntax-only -verify %s -fblocks - -struct S { - int i : 1; - int j; -}; - -void run(void (^)()); -void test() { - auto [i, j] = S{1, 42}; // expected-note {{'i' declared here}} - run(^{ - (void)i; // expected-error {{reference to local binding 'i' declared in enclosing function 'test'}} - }); -} diff --git a/clang/test/SemaCXX/decomposition-openmp.cpp b/clang/test/SemaCXX/decomposition-openmp.cpp deleted file mode 100644 index 28afc398..0000000 --- a/clang/test/SemaCXX/decomposition-openmp.cpp +++ /dev/null @@ -1,13 +0,0 @@ - -// RUN: %clang_cc1 -fsyntax-only -verify -std=c++20 -fopenmp %s - -// FIXME: OpenMP should support capturing structured bindings -auto f() { - int i[2] = {}; - auto [a, b] = i; // expected-note 2{{declared here}} - return [=, &a] { - // expected-error@-1 {{capturing a structured binding is not yet supported in OpenMP}} - return a + b; - // expected-error@-1 {{capturing a structured binding is not yet supported in OpenMP}} - }; -} diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp index b3f91ef..9356dd4 100644 --- a/clang/tools/libclang/CIndex.cpp +++ b/clang/tools/libclang/CIndex.cpp @@ -3482,11 +3482,9 @@ bool CursorVisitor::RunVisitorWorkList(VisitorWorkList &WL) { C != CEnd; ++C) { if (!C->capturesVariable()) continue; - // TODO: handle structured bindings here ? - if (!isa(C->getCapturedVar())) - continue; - if (Visit(MakeCursorVariableRef(cast(C->getCapturedVar()), - C->getLocation(), TU))) + + if (Visit(MakeCursorVariableRef(C->getCapturedVar(), C->getLocation(), + TU))) return true; } // Visit init captures diff --git a/clang/www/cxx_status.html b/clang/www/cxx_status.html index 5aae4ba..41b788e 100755 --- a/clang/www/cxx_status.html +++ b/clang/www/cxx_status.html @@ -1140,7 +1140,7 @@ code. This issue is expected to be rectified soon. Structured binding extensions P1091R3 - Clang 16 + Partial P1381R1