cor3ntin created this revision.
Herald added a project: All.
cor3ntin requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Partially implement the proposed resolution to CWG2569.

D119136 <https://reviews.llvm.org/D119136> broke some libstdc++ code, as 
P2036R3, implemented as a DR to
C++11 made ill-formed some previously valid and innocuous code.

We resolve this issue to allow decltype(x) - but not decltype((x)
to appear in the parameter list of a lambda that capture x by copy.

Unlike CWG2569, we do not extend that special treatment to
sizeof/noexcept yet, as the resolution has not been approved yet
and keeping the review small allows a quicker fix of impacted code.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D123909

Files:
  clang/include/clang/Parse/Parser.h
  clang/include/clang/Sema/Sema.h
  clang/lib/Parse/ParseDeclCXX.cpp
  clang/lib/Parse/ParseExprCXX.cpp
  clang/lib/Sema/SemaExpr.cpp
  clang/test/SemaCXX/lambda-capture-type-deduction.cpp

Index: clang/test/SemaCXX/lambda-capture-type-deduction.cpp
===================================================================
--- clang/test/SemaCXX/lambda-capture-type-deduction.cpp
+++ clang/test/SemaCXX/lambda-capture-type-deduction.cpp
@@ -87,23 +87,23 @@
   int y, z;                // expected-note 2{{declared here}}
   auto implicit_tpl = [=]( // expected-note {{variable 'y' is captured here}}
                           decltype(
-                              [&]<decltype(y)> { return 0; }) y) { //expected-error{{captured variable 'y' cannot appear here}}
+                              [&]<decltype((y))> { return 0; }) y) { // expected-error{{captured variable 'y' cannot appear here}}
     return y;
   };
 
-  auto init_tpl = [x = 1](                                          // expected-note{{explicitly captured here}}
-                      decltype([&]<decltype(x)> { return 0; }) y) { // expected-error {{captured variable 'x' cannot appear here}}
+  auto init_tpl = [x = 1](                                            // expected-note{{explicitly captured here}}
+                      decltype([&]<decltype((x))> { return 0; }) y) { // expected-error {{captured variable 'x' cannot appear here}}
     return x;
   };
 
   auto implicit = [=]( // expected-note {{variable 'z' is captured here}}
                       decltype(
-                          [&](decltype(z)) { return 0; }) z) { //expected-error{{captured variable 'z' cannot appear here}}
+                          [&](decltype((z))) { return 0; }) z) { // expected-error{{captured variable 'z' cannot appear here}}
     return z;
   };
 
-  auto init = [x = 1](                                          // expected-note{{explicitly captured here}}
-                  decltype([&](decltype(x)) { return 0; }) y) { // expected-error {{captured variable 'x' cannot appear here}}
+  auto init = [x = 1](                                            // expected-note{{explicitly captured here}}
+                  decltype([&](decltype((x))) { return 0; }) y) { // expected-error {{captured variable 'x' cannot appear here}}
     return x;
   };
 
@@ -141,20 +141,20 @@
       decltype([&](
                    decltype([=]( // expected-note {{variable 'x' is captured here}}
                                 decltype([&](
-                                             decltype([&](decltype(x)) {}) // expected-error{{captured variable 'x' cannot appear here}}
+                                             decltype([&](decltype((x))) {}) // expected-error{{captured variable 'x' cannot appear here}}
                                          ) {})) {})) {})){};
 
   (void)[&](
       decltype([&](
                    decltype([&](
                                 decltype([&](
-                                             decltype([&](decltype(y)) {})) {})) {})) {})){};
+                                             decltype([&](decltype((y))) {})) {})) {})) {})){};
 
   (void)[=](
       decltype([=](
                    decltype([=](
-                                decltype([=](                              // expected-note {{variable 'z' is captured here}}
-                                             decltype([&]<decltype(z)> {}) // expected-error{{captured variable 'z' cannot appear here}}
+                                decltype([=](                                // expected-note {{variable 'z' is captured here}}
+                                             decltype([&]<decltype((z))> {}) // expected-error{{captured variable 'z' cannot appear here}}
                                          ) {})) {})) {})){};
 }
 
@@ -171,3 +171,13 @@
   dependent<int&>(r);
   dependent<const int&>(cr);
 }
+
+void test_CWG2569_tpl(auto a) {
+  (void)[=]<typename T = decltype(a)>(decltype(a) b = decltype(a)()){};
+}
+
+void test_CWG2569() {
+  int a = 0;
+  (void)[=]<typename T = decltype(a)>(decltype(a) b = decltype(a)()){};
+  test_CWG2569_tpl(0);
+}
Index: clang/lib/Sema/SemaExpr.cpp
===================================================================
--- clang/lib/Sema/SemaExpr.cpp
+++ clang/lib/Sema/SemaExpr.cpp
@@ -2698,6 +2698,21 @@
   return BuildDeclarationNameExpr(SS, R, ADL);
 }
 
+ExprResult Sema::ActOnMutableAgnosticIdExpression(Scope *S, CXXScopeSpec &SS,
+                                                  UnqualifiedId &Id,
+                                                  SourceLocation TemplateKwLoc,
+                                                  bool HasTrailingLParen) {
+  InMutableAgnosticContext = true;
+  ExprResult Res =
+      ActOnIdExpression(S, SS, TemplateKwLoc, Id, HasTrailingLParen,
+                        /*IsAddressOfOperand*/ false,
+                        /*CorrectionCandidateCallback*/ nullptr,
+                        /*IsInlineAsmIdentifier*/ false,
+                        /*KeywordReplacement*/ nullptr);
+  InMutableAgnosticContext = false;
+  return Res;
+}
+
 /// BuildQualifiedDeclarationNameExpr - Build a C++ qualified
 /// declaration name, generally during template instantiation.
 /// There's a large number of things which don't need to be done along
@@ -18545,6 +18560,11 @@
 static bool CheckCaptureUseBeforeLambdaQualifiers(Sema &S, VarDecl *Var,
                                                   SourceLocation ExprLoc,
                                                   LambdaScopeInfo *LSI) {
+
+  // Allow `[a = 1](decltype(a)) {}` as per CWG2569.
+  if (S.InMutableAgnosticContext)
+    return true;
+
   if (Var->isInvalidDecl())
     return false;
 
@@ -18627,7 +18647,7 @@
       LSI = dyn_cast_or_null<LambdaScopeInfo>(
           FunctionScopes[FunctionScopesIndex]);
     if (LSI && LSI->BeforeLambdaQualifiersScope) {
-      if (isa<ParmVarDecl>(Var))
+      if (isa<ParmVarDecl>(Var) && !Var->getDeclContext()->isFunctionOrMethod())
         return true;
       IsInLambdaBeforeQualifiers = true;
       if (!CheckCaptureUseBeforeLambdaQualifiers(*this, Var, ExprLoc, LSI)) {
Index: clang/lib/Parse/ParseExprCXX.cpp
===================================================================
--- clang/lib/Parse/ParseExprCXX.cpp
+++ clang/lib/Parse/ParseExprCXX.cpp
@@ -685,6 +685,36 @@
   return Result;
 }
 
+/// ParseCXXMaybeMutableAgnosticExpression - Handle Expressions inside of
+/// sizeof, decltype, noexcepr
+/// - unqualified-id
+/// - expression
+/// This serves to silence errors about captured variable refered in lambda
+/// parameter list, if they aree used as the unqualified-id of a decltype,
+/// sizeof, or noexcept expression
+ExprResult Parser::ParseCXXMaybeMutableAgnosticExpression() {
+
+  if (!getLangOpts().CPlusPlus11)
+    return ParseExpression();
+
+  if (Tok.is(tok::identifier) && NextToken().is(tok::r_paren)) {
+    SourceLocation TemplateKWLoc;
+    UnqualifiedId Name;
+    CXXScopeSpec SS;
+    if (!ParseUnqualifiedId(SS, /*ObjectType=*/nullptr,
+                            /*ObjectHadErrors=*/false,
+                            /*EnteringContext=*/false,
+                            /*AllowDestructorName=*/false,
+                            /*AllowConstructorName=*/false,
+                            /*AllowDeductionGuide=*/false, &TemplateKWLoc,
+                            Name)) {
+      return Actions.ActOnMutableAgnosticIdExpression(getCurScope(), SS, Name,
+                                                      TemplateKWLoc, false);
+    }
+  }
+  return ParseExpression();
+}
+
 /// ParseLambdaExpression - Parse a C++11 lambda expression.
 ///
 ///       lambda-expression:
Index: clang/lib/Parse/ParseDeclCXX.cpp
===================================================================
--- clang/lib/Parse/ParseDeclCXX.cpp
+++ clang/lib/Parse/ParseDeclCXX.cpp
@@ -1054,7 +1054,7 @@
           Actions, Sema::ExpressionEvaluationContext::Unevaluated, nullptr,
           Sema::ExpressionEvaluationContextRecord::EK_Decltype);
       Result = Actions.CorrectDelayedTyposInExpr(
-          ParseExpression(), /*InitDecl=*/nullptr,
+          ParseCXXMaybeMutableAgnosticExpression(), /*InitDecl=*/nullptr,
           /*RecoverUncorrectedTypos=*/false,
           [](Expr *E) { return E->hasPlaceholderType() ? ExprError() : E; });
       if (Result.isInvalid()) {
Index: clang/include/clang/Sema/Sema.h
===================================================================
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -787,6 +787,11 @@
   /// context.
   unsigned FunctionScopesStart = 0;
 
+  /// Whether we are currently in the context of a mutable agnostic identifier
+  /// as described by CWG2569.
+  /// We are handling the unqualified-id of a decltype or noexcept expression.
+  bool InMutableAgnosticContext = false;
+
   ArrayRef<sema::FunctionScopeInfo*> getFunctionScopes() const {
     return llvm::makeArrayRef(FunctionScopes.begin() + FunctionScopesStart,
                               FunctionScopes.end());
@@ -5270,6 +5275,11 @@
       CorrectionCandidateCallback *CCC = nullptr,
       bool IsInlineAsmIdentifier = false, Token *KeywordReplacement = nullptr);
 
+  ExprResult ActOnMutableAgnosticIdExpression(Scope *S, CXXScopeSpec &SS,
+                                              UnqualifiedId &Id,
+                                              SourceLocation TemplateKwLoc,
+                                              bool HasTrailingLParen);
+
   void DecomposeUnqualifiedId(const UnqualifiedId &Id,
                               TemplateArgumentListInfo &Buffer,
                               DeclarationNameInfo &NameInfo,
Index: clang/include/clang/Parse/Parser.h
===================================================================
--- clang/include/clang/Parse/Parser.h
+++ clang/include/clang/Parse/Parser.h
@@ -1861,6 +1861,8 @@
                                      Token &Replacement);
   ExprResult ParseCXXIdExpression(bool isAddressOfOperand = false);
 
+  ExprResult ParseCXXMaybeMutableAgnosticExpression();
+
   bool areTokensAdjacent(const Token &A, const Token &B);
 
   void CheckForTemplateAndDigraph(Token &Next, ParsedType ObjectTypePtr,
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to