[clang] 467ed27 - [clang] Extend pragma dump to support expressions

Vlad Serebrennikov via cfe-commits cfe-commits at lists.llvm.org
Fri Mar 24 07:36:35 PDT 2023


Author: Vlad Serebrennikov
Date: 2023-03-24T17:35:35+03:00
New Revision: 467ed2798772344e2a3b4a8d368575f1f9d1a8c6

URL: https://github.com/llvm/llvm-project/commit/467ed2798772344e2a3b4a8d368575f1f9d1a8c6
DIFF: https://github.com/llvm/llvm-project/commit/467ed2798772344e2a3b4a8d368575f1f9d1a8c6.diff

LOG: [clang] Extend pragma dump to support expressions

Extend `#pragma clang __debug dump` to support not only single identifier, but an expression as well. This makes it possible to test ADL and overload resolution directly, without being creative to make them observable via diagnostics (e.g. when [[ http://eel.is/c++draft/over.match.best | over.match.best ]] is involved). This implementation has a known limitation of not supporting dependent expressions properly, but it's quite useful even without such support.

Differential Revision: https://reviews.llvm.org/D144115

Added: 
    

Modified: 
    clang/docs/LanguageExtensions.rst
    clang/docs/ReleaseNotes.rst
    clang/include/clang/Basic/DiagnosticCommonKinds.td
    clang/include/clang/Basic/DiagnosticLexKinds.td
    clang/include/clang/Basic/DiagnosticParseKinds.td
    clang/include/clang/Sema/Sema.h
    clang/lib/Lex/Pragma.cpp
    clang/lib/Parse/ParsePragma.cpp
    clang/lib/Sema/SemaLookup.cpp
    clang/test/AST/ast-dump-lookups.cpp

Removed: 
    


################################################################################
diff  --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst
index b68d44e75e9b5..cda08066c6ab2 100644
--- a/clang/docs/LanguageExtensions.rst
+++ b/clang/docs/LanguageExtensions.rst
@@ -4917,3 +4917,21 @@ The following x86-specific intrinsics can be used in constant expressions:
 * ``_rotwr``
 * ``_lrotl``
 * ``_lrotr``
+
+Debugging the Compiler
+======================
+
+Clang supports a number of pragma directives that help debugging the compiler itself.
+Syntax is the following: `#pragma clang __debug <command> <arguments>`.
+Note, all of debugging pragmas are subject to change.
+
+`dump`
+------
+Accepts either a single identifier or an expression. When a single identifier is passed,
+the lookup results for the identifier are printed to `stderr`. When an expression is passed, 
+the AST for the expression is printed to `stderr`. The expression is an unevaluated operand,
+so things like overload resolution and template instantiations are performed,
+but the expression has no runtime effects.
+Type- and value-dependent expressions are not supported yet.
+
+This facility is designed to aid with testing name lookup machinery.

diff  --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 29e3f516c06e5..526ea11303708 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -126,6 +126,7 @@ Non-comprehensive list of changes in this release
   from the invocation point, with no path components included).
 - Clang now supports ``__builtin_assume_separate_storage`` that indicates that
   its arguments point to objects in separate storage allocations.
+- Clang now supports expressions in ``#pragma clang __debug dump``.
 
 New Compiler Flags
 ------------------

diff  --git a/clang/include/clang/Basic/DiagnosticCommonKinds.td b/clang/include/clang/Basic/DiagnosticCommonKinds.td
index 9b8103c97e39c..f574b0f0171b7 100644
--- a/clang/include/clang/Basic/DiagnosticCommonKinds.td
+++ b/clang/include/clang/Basic/DiagnosticCommonKinds.td
@@ -63,6 +63,10 @@ def err_invalid_character_udl : Error<
   "character literal with user-defined suffix cannot be used here">;
 def err_invalid_numeric_udl : Error<
   "numeric literal with user-defined suffix cannot be used here">;
+def warn_pragma_debug_missing_argument : Warning<
+  "missing argument to debug command '%0'">, InGroup<IgnoredPragmas>;
+def warn_pragma_debug_unexpected_argument : Warning<
+  "unexpected argument to debug command">, InGroup<IgnoredPragmas>;
 
 }
 

diff  --git a/clang/include/clang/Basic/DiagnosticLexKinds.td b/clang/include/clang/Basic/DiagnosticLexKinds.td
index fbb08a6f761be..b77c19b816d86 100644
--- a/clang/include/clang/Basic/DiagnosticLexKinds.td
+++ b/clang/include/clang/Basic/DiagnosticLexKinds.td
@@ -655,10 +655,6 @@ def warn_pragma_debug_missing_command : Warning<
   "missing debug command">, InGroup<IgnoredPragmas>;
 def warn_pragma_debug_unexpected_command : Warning<
   "unexpected debug command '%0'">, InGroup<IgnoredPragmas>;
-def warn_pragma_debug_missing_argument : Warning<
-  "missing argument to debug command '%0'">, InGroup<IgnoredPragmas>;
-def warn_pragma_debug_unexpected_argument : Warning<
-  "unexpected argument to debug command">, InGroup<IgnoredPragmas>;
 def warn_pragma_debug_unknown_module : Warning<
   "unknown module '%0'">, InGroup<IgnoredPragmas>;
 // #pragma module

diff  --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td
index 2ad4d98f0ed88..929ba9e3287ef 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -1300,6 +1300,10 @@ def note_pragma_attribute_namespace_on_attribute : Note<
 def warn_no_support_for_eval_method_source_on_m32 : Warning<
   "Setting the floating point evaluation method to `source` on a target"
   " without SSE is not supported.">, InGroup<Pragmas>;
+// - #pragma __debug
+def warn_pragma_debug_dependent_argument : Warning<
+  "%select{value|type}0-dependent expression passed as an argument to debug "
+  "command">, InGroup<IgnoredPragmas>;
 
 // OpenCL EXTENSION pragma (OpenCL 1.1 [9.1])
 def warn_pragma_expected_colon : Warning<

diff  --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 277c02ee3f1bd..9f7d58a4a3cd6 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -10703,6 +10703,9 @@ class Sema final {
   /// Called on #pragma clang __debug dump II
   void ActOnPragmaDump(Scope *S, SourceLocation Loc, IdentifierInfo *II);
 
+  /// Called on #pragma clang __debug dump E
+  void ActOnPragmaDump(Expr *E);
+
   /// ActOnPragmaDetectMismatch - Call on well-formed \#pragma detect_mismatch
   void ActOnPragmaDetectMismatch(SourceLocation Loc, StringRef Name,
                                  StringRef Value);

diff  --git a/clang/lib/Lex/Pragma.cpp b/clang/lib/Lex/Pragma.cpp
index bc2b6b1094367..db8a5891679f4 100644
--- a/clang/lib/Lex/Pragma.cpp
+++ b/clang/lib/Lex/Pragma.cpp
@@ -1066,21 +1066,11 @@ struct PragmaDebugHandler : public PragmaHandler {
         PP.EnterToken(Crasher, /*IsReinject*/ false);
       }
     } else if (II->isStr("dump")) {
-      Token Identifier;
-      PP.LexUnexpandedToken(Identifier);
-      if (auto *DumpII = Identifier.getIdentifierInfo()) {
-        Token DumpAnnot;
-        DumpAnnot.startToken();
-        DumpAnnot.setKind(tok::annot_pragma_dump);
-        DumpAnnot.setAnnotationRange(
-            SourceRange(Tok.getLocation(), Identifier.getLocation()));
-        DumpAnnot.setAnnotationValue(DumpII);
-        PP.DiscardUntilEndOfDirective();
-        PP.EnterToken(DumpAnnot, /*IsReinject*/false);
-      } else {
-        PP.Diag(Identifier, diag::warn_pragma_debug_missing_argument)
-            << II->getName();
-      }
+      Token DumpAnnot;
+      DumpAnnot.startToken();
+      DumpAnnot.setKind(tok::annot_pragma_dump);
+      DumpAnnot.setAnnotationRange(SourceRange(Tok.getLocation()));
+      PP.EnterToken(DumpAnnot, /*IsReinject*/false);
     } else if (II->isStr("diag_mapping")) {
       Token DiagName;
       PP.LexUnexpandedToken(DiagName);

diff  --git a/clang/lib/Parse/ParsePragma.cpp b/clang/lib/Parse/ParsePragma.cpp
index ff7273eddb1a0..4c7ca8f540bdc 100644
--- a/clang/lib/Parse/ParsePragma.cpp
+++ b/clang/lib/Parse/ParsePragma.cpp
@@ -706,10 +706,36 @@ void Parser::HandlePragmaAlign() {
 
 void Parser::HandlePragmaDump() {
   assert(Tok.is(tok::annot_pragma_dump));
-  IdentifierInfo *II =
-      reinterpret_cast<IdentifierInfo *>(Tok.getAnnotationValue());
-  Actions.ActOnPragmaDump(getCurScope(), Tok.getLocation(), II);
   ConsumeAnnotationToken();
+  if (Tok.is(tok::eod)) {
+    PP.Diag(Tok, diag::warn_pragma_debug_missing_argument) << "dump";
+  } else if (NextToken().is(tok::eod)) {
+    if (Tok.isNot(tok::identifier)) {
+      PP.Diag(Tok, diag::warn_pragma_debug_unexpected_argument);
+      ConsumeAnyToken();
+      ExpectAndConsume(tok::eod);
+      return;
+    }
+    IdentifierInfo *II = Tok.getIdentifierInfo();
+    Actions.ActOnPragmaDump(getCurScope(), Tok.getLocation(), II);
+    ConsumeToken();
+  } else {
+    SourceLocation StartLoc = Tok.getLocation();
+    EnterExpressionEvaluationContext Ctx(
+      Actions, Sema::ExpressionEvaluationContext::Unevaluated);
+    ExprResult E = ParseExpression();
+    if (!E.isUsable() || E.get()->containsErrors()) {
+      // Diagnostics were emitted during parsing. No action needed.
+    } else if (E.get()->getDependence() != ExprDependence::None) {
+      PP.Diag(StartLoc, diag::warn_pragma_debug_dependent_argument)
+        << E.get()->isTypeDependent()
+        << SourceRange(StartLoc, Tok.getLocation());
+    } else {
+      Actions.ActOnPragmaDump(E.get());
+    }
+    SkipUntil(tok::eod, StopBeforeMatch);
+  }
+  ExpectAndConsume(tok::eod);
 }
 
 void Parser::HandlePragmaWeak() {

diff  --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp
index 09a38571762d5..2413f31744c53 100644
--- a/clang/lib/Sema/SemaLookup.cpp
+++ b/clang/lib/Sema/SemaLookup.cpp
@@ -5841,3 +5841,7 @@ void Sema::ActOnPragmaDump(Scope *S, SourceLocation IILoc, IdentifierInfo *II) {
   LookupName(R, S);
   R.dump();
 }
+
+void Sema::ActOnPragmaDump(Expr *E) {
+  E->dump();
+}

diff  --git a/clang/test/AST/ast-dump-lookups.cpp b/clang/test/AST/ast-dump-lookups.cpp
index 2d235010cb735..58f31ac4a3a6d 100644
--- a/clang/test/AST/ast-dump-lookups.cpp
+++ b/clang/test/AST/ast-dump-lookups.cpp
@@ -1,7 +1,7 @@
 // RUN: %clang_cc1 -std=c++11 -ast-dump -ast-dump-filter Test %s | FileCheck -check-prefix DECLS %s
 // RUN: %clang_cc1 -std=c++11 -ast-dump-lookups -ast-dump-filter Test %s | FileCheck -check-prefix LOOKUPS %s
 // RUN: %clang_cc1 -std=c++11 -ast-dump -ast-dump-lookups -ast-dump-filter Test %s | FileCheck -check-prefix DECLS-LOOKUPS %s
-// RUN: %clang_cc1 -std=c++11 -DPRAGMA -fsyntax-only %s 2>&1 | FileCheck -check-prefix PRAGMA %s
+// RUN: %clang_cc1 -std=c++11 -DPRAGMA -fsyntax-only -verify %s 2>&1 | FileCheck -check-prefix PRAGMA %s
 
 namespace Test {
   typedef int T;
@@ -51,3 +51,50 @@ namespace Test { }
 //
 // DECLS-LOOKUPS: Dumping Test:
 // DECLS-LOOKUPS-NEXT: Lookup map is in primary DeclContext
+
+#ifdef PRAGMA
+namespace Test {
+  struct S {
+    const S& operator+(const S&) { return *this; }
+  };
+  void foo(S) {}
+}
+
+#pragma clang __debug dump foo(Test::S{})
+// PRAGMA: CallExpr {{.*}} adl
+// PRAGMA-NEXT: |-ImplicitCastExpr {{.*}}
+// PRAGMA-NEXT: | `-DeclRefExpr {{.*}} 'void (S)' lvalue Function {{.*}} 'foo' 'void (S)'
+
+#pragma clang __debug dump Test::S{} + Test::S{}
+// PRAGMA: CXXOperatorCallExpr {{.*}}
+// PRAGMA-NEXT: |-ImplicitCastExpr {{.*}}
+// PRAGMA-NEXT: | `-DeclRefExpr {{.*}} 'const S &(const S &)' lvalue CXXMethod {{.*}} 'operator+' 'const S &(const S &)'
+
+#pragma clang __debug dump &Test::S::operator+
+// PRAGMA: UnaryOperator {{.*}}
+// PRAGMA-NEXT: `-DeclRefExpr {{.*}} 'const S &(const S &)' CXXMethod {{.*}} 'operator+' 'const S &(const S &)'
+
+template<typename T, int I>
+void bar() {
+#pragma clang __debug dump T{} // expected-warning {{type-dependent expression}}
+#pragma clang __debug dump +I  // expected-warning {{value-dependent expression}}
+}
+
+template <typename T>
+struct S {
+  static constexpr const T *str = "string";
+};
+
+template <>
+struct S<wchar_t> {
+  static constexpr const wchar_t *str = L"wide string";
+};
+
+void func() {
+  #pragma clang __debug dump S<wchar_t>::str;
+  // PRAGMA: DeclRefExpr {{.*}} 'const wchar_t *const' lvalue Var {{.*}} 'str' 'const wchar_t *const'
+}
+
+#pragma clang __debug dump this is nonsense // expected-error {{invalid use of 'this'}}
+
+#endif


        


More information about the cfe-commits mailing list