[PATCH] D153536: [Clang] Implement P2169 A nice placeholder with no name

Aaron Ballman via Phabricator via cfe-commits cfe-commits at lists.llvm.org
Tue Jun 27 09:28:07 PDT 2023


aaron.ballman added subscribers: cjdb, aaron.ballman.
aaron.ballman added inline comments.


================
Comment at: clang/docs/ReleaseNotes.rst:135-136
 - Compiler flags ``-std=c++2c`` and ``-std=gnu++2c`` have been added for experimental C++2c implementation work.
+- Implemented `P2169R4: A nice placeholder with no name <https://wg21.link/P2169R4>`_. This allows to use `_`
+  as a variable name multiple times in the same scope and is supported in all C++ language modes as an extension.
 
----------------
Should we consider adding this as an extension to C? It would be conforming there as well because it wouldn't change the behavior of any correct C code, right?


================
Comment at: clang/include/clang/AST/DeclBase.h:340-342
+  /// Whether this declaration denotes a placeholder that can be
+  /// redefined in the same scope.
+  unsigned IsPlaceholder : 1;
----------------
This seems a bit heavy to put on every `Decl`, it only matters for declarations with names, right? Should this be on `NamedDecl` instead? And should it be using terminology like "name independent"?

Actually, do we need this bit at all? Would it work for `NamedDecl` to have a function that returns whether the declaration name is `_` or not? Oh, I suppose we can't get away with that because `void _(int x);` does not introduce a placeholder identifier but a regular one, right?


================
Comment at: clang/include/clang/Basic/DiagnosticSemaKinds.td:6589
+def err_using_placeholder_variable : Error<
+  "referring to placeholder '_' is not allowed">;
+def note_reference_placeholder : Note<
----------------
I don't think this helps the user understand what's wrong with their code, especially given the somewhat odd language rules around the feature. How about: `ambiguous reference to multiply-defined placeholder '_'` or something along those lines? Then the note can show the previous declarations of the placeholders that are in scope? e.g.,
```
void g() {
int _; // note: placeholder declared here
_ = 0;
int _; // note: placeholder declared here
_ = 0; // error: `ambiguous reference to multiply-defined placeholder '_'`
}
```
CC @cjdb 


================
Comment at: clang/include/clang/Sema/Lookup.h:121
+    /// Name lookup results in an ambiguity because multiple placeholder
+    /// variables were found in the same scope
+    /// @code
----------------



================
Comment at: clang/lib/Sema/SemaDecl.cpp:2171-2172
 
+  if (VD->isPlaceholderVar())
+    return;
+
----------------
What's the rationale here? I know the standard has a recommended practice, but I don't see why that should apply to the case where the user assigns a value to the placeholder but never references it otherwise.


================
Comment at: clang/lib/Sema/SemaDecl.cpp:7481
+    if (!Previous.empty()) {
+      auto Decl = *Previous.begin();
+      const bool sameDC = Decl->getDeclContext()->getRedeclContext()->Equals(
----------------
Please spell out the type here.


================
Comment at: clang/lib/Sema/SemaDecl.cpp:7482
+      auto Decl = *Previous.begin();
+      const bool sameDC = Decl->getDeclContext()->getRedeclContext()->Equals(
+          DC->getRedeclContext());
----------------



================
Comment at: clang/lib/Sema/SemaDecl.cpp:7484-7486
+      if (sameDC && isDeclInScope(Decl, CurContext, S, false)) {
+        DiagPlaceholderVariableDefinition(D.getIdentifierLoc());
+      }
----------------



================
Comment at: clang/lib/Sema/SemaDecl.cpp:8331
 
+  // Never warn about shadowing placeholder variable
+  if (ShadowedDecl->isPlaceholderVar())
----------------



================
Comment at: clang/lib/Sema/SemaDecl.cpp:18217
 
+  NewFD->setIsPlaceholderVar(LangOpts.CPlusPlus && II && II->isPlaceholder());
   if (PrevDecl && !isa<TagDecl>(PrevDecl)) {
----------------
shafik wrote:
> cor3ntin wrote:
> > shafik wrote:
> > > Why can't we fold this into `FieldDecl::Create`? This comment applies in some other places as well.
> > By adding a parameter to FieldDecl::Create? We could, I'm not sure it would necessarily be cleaner. Let me know what you prefer.
> It seems like having the code consolidated make for better maintainability and figuring this out for future folks but I am willing to be convinced otherwise.
We need to support partial construction because of AST deserialization, but it seems to me that we don't need to add a new parameter to `FieldDecl::Create()` anyway; can't we have the `FieldDecl` constructor look at the given `IdentifierInfo *` in that case, and if it's nonnull, set the placeholder from that?


================
Comment at: clang/lib/Sema/SemaDeclCXX.cpp:886
     DeclarationNameInfo NameInfo(B.Name, B.NameLoc);
+    IdentifierInfo *VarName = B.Name;
     LookupResult Previous(*this, NameInfo, LookupOrdinaryName,
----------------
`assert(VarName && "Cannot have an unnamed binding declaration");` ?


================
Comment at: clang/lib/Sema/SemaDeclCXX.cpp:917
+      if (IsPlaceholder) {
+        const bool sameDC = (Previous.end() - 1)
+                                ->getDeclContext()
----------------



================
Comment at: clang/lib/Sema/SemaLambda.cpp:1151-1153
+    if (Var && Var->isInitCapture() && C->Id->isPlaceholder()) {
+      Var->setIsPlaceholderVar(true);
+    }
----------------



================
Comment at: clang/test/SemaCXX/cxx2c-placeholder-vars.cpp:31
+                           // expected-note 4{{placeholder declared here}} \\
+                           // expected-warning 2{{placeholder variable has no side effect}}
+        (void)_++; // expected-error {{referring to placeholder '_' is not allowed}}
----------------
I don't understand what this diagnostic is trying to tell me, can you explain a bit more?


================
Comment at: clang/test/SemaCXX/cxx2c-placeholder-vars.cpp:79
+void test_param(int _) {}
+void test_params(int _, int _); // expected-error {{redefinition of parameter '_'}} \
+                                // expected-note {{previous declaration is here}}
----------------
Weird.. is this expected? You can have two variables named `_` in block scope, but you can't have two parameters named `_` despite them inhabiting the same block scope?


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D153536/new/

https://reviews.llvm.org/D153536



More information about the cfe-commits mailing list