[clang] 0478720 - [clang] Prevent that Decl::dump on a CXXRecordDecl deserialises further declarations.

Raphael Isemann via cfe-commits cfe-commits at lists.llvm.org
Mon Sep 7 03:32:10 PDT 2020


Author: Raphael Isemann
Date: 2020-09-07T12:31:30+02:00
New Revision: 0478720157f6413fad7595b8eff9c70d2d99b637

URL: https://github.com/llvm/llvm-project/commit/0478720157f6413fad7595b8eff9c70d2d99b637
DIFF: https://github.com/llvm/llvm-project/commit/0478720157f6413fad7595b8eff9c70d2d99b637.diff

LOG: [clang] Prevent that Decl::dump on a CXXRecordDecl deserialises further declarations.

Decl::dump is primarily used for debugging to visualise the current state of a
declaration. Usually Decl::dump just displays the current state of the Decl and
doesn't actually change any of its state, however since commit
457226e02a6e8533eaaa864a3fd7c8eeccd2bf58 the method actually started loading
additional declarations from the ExternalASTSource. This causes that calling
Decl::dump during a debugging session now actually does permanent changes to the
AST and will cause the debugged program run to deviate from the original run.

The change that caused this behaviour is the addition of
`hasConstexprDestructor` (which is called from the TextNodeDumper) which
performs a lookup into the current CXXRecordDecl to find the destructor. All
other similar methods just return their respective bit in the DefinitionData
(which obviously doesn't have such side effects).

This just changes the node printer to emit "unknown_constexpr" in case a
CXXRecordDecl is dumped that could potentially call into the ExternalASTSource
instead of the usually empty string/"constexpr". For CXXRecordDecls that can
safely be dumped the old behaviour is preserved

Reviewed By: bruno

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

Added: 
    clang/unittests/AST/ASTDumpTest.cpp

Modified: 
    clang/lib/AST/TextNodeDumper.cpp
    clang/test/AST/ast-dump-lambda.cpp
    clang/test/AST/ast-dump-records.cpp
    clang/unittests/AST/CMakeLists.txt

Removed: 
    


################################################################################
diff  --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp
index 16c4c3736a4a..19b7b4c801d5 100644
--- a/clang/lib/AST/TextNodeDumper.cpp
+++ b/clang/lib/AST/TextNodeDumper.cpp
@@ -1960,7 +1960,11 @@ void TextNodeDumper::VisitCXXRecordDecl(const CXXRecordDecl *D) {
       FLAG(hasTrivialDestructor, trivial);
       FLAG(hasNonTrivialDestructor, non_trivial);
       FLAG(hasUserDeclaredDestructor, user_declared);
-      FLAG(hasConstexprDestructor, constexpr);
+      // Avoid calls to the external source.
+      if (!D->hasExternalVisibleStorage()) {
+        FLAG(hasConstexprDestructor, constexpr);
+      } else
+        OS << " maybe_constexpr";
       FLAG(needsImplicitDestructor, needs_implicit);
       FLAG(needsOverloadResolutionForDestructor, needs_overload_resolution);
       if (!D->needsOverloadResolutionForDestructor())

diff  --git a/clang/test/AST/ast-dump-lambda.cpp b/clang/test/AST/ast-dump-lambda.cpp
index 37fb62ef9930..302b93734459 100644
--- a/clang/test/AST/ast-dump-lambda.cpp
+++ b/clang/test/AST/ast-dump-lambda.cpp
@@ -48,7 +48,7 @@ template <typename... Ts> void test(Ts... a) {
 // CHECK-NEXT:    |   | |-MoveConstructor exists simple trivial needs_implicit
 // CHECK-NEXT:    |   | |-CopyAssignment simple trivial has_const_param needs_implicit implicit_has_const_param
 // CHECK-NEXT:    |   | |-MoveAssignment exists simple trivial needs_implicit
-// CHECK-NEXT:    |   | `-Destructor simple irrelevant trivial needs_implicit
+// CHECK-NEXT:    |   | `-Destructor simple irrelevant trivial{{( maybe_constexpr)?}} needs_implicit
 // CHECK-NEXT:    |   |-CXXRecordDecl {{.*}} <col:3, col:10> col:10{{( imported)?}} implicit struct V
 // CHECK-NEXT:    |   `-CXXMethodDecl {{.*}} <line:17:5, line:20:5> line:17:10{{( imported)?}} f 'void ()'
 // CHECK-NEXT:    |     `-CompoundStmt {{.*}} <col:14, line:20:5>
@@ -60,7 +60,7 @@ template <typename... Ts> void test(Ts... a) {
 // CHECK-NEXT:    |       | | | |-MoveConstructor exists simple trivial needs_implicit
 // CHECK-NEXT:    |       | | | |-CopyAssignment trivial has_const_param needs_implicit implicit_has_const_param
 // CHECK-NEXT:    |       | | | |-MoveAssignment
-// CHECK-NEXT:    |       | | | `-Destructor simple irrelevant trivial needs_implicit
+// CHECK-NEXT:    |       | | | `-Destructor simple irrelevant trivial{{( maybe_constexpr)?}} needs_implicit
 // CHECK-NEXT:    |       | | |-CXXMethodDecl {{.*}} <col:12, col:15> col:7{{( imported)?}} operator() 'auto () const -> auto' inline
 // CHECK-NEXT:    |       | | | `-CompoundStmt {{.*}} <col:14, col:15>
 // CHECK-NEXT:    |       | | `-FieldDecl {{.*}} <col:8> col:8{{( imported)?}} implicit 'V *'
@@ -75,7 +75,7 @@ template <typename... Ts> void test(Ts... a) {
 // CHECK-NEXT:    |         | | |-MoveConstructor exists simple trivial needs_implicit
 // CHECK-NEXT:    |         | | |-CopyAssignment trivial has_const_param needs_implicit implicit_has_const_param
 // CHECK-NEXT:    |         | | |-MoveAssignment
-// CHECK-NEXT:    |         | | `-Destructor simple irrelevant trivial needs_implicit
+// CHECK-NEXT:    |         | | `-Destructor simple irrelevant trivial{{( maybe_constexpr)?}} needs_implicit
 // CHECK-NEXT:    |         | |-CXXMethodDecl {{.*}} <col:13, col:16> col:7{{( imported)?}} operator() 'auto () const -> auto' inline
 // CHECK-NEXT:    |         | | `-CompoundStmt {{.*}} <col:15, col:16>
 // CHECK-NEXT:    |         | `-FieldDecl {{.*}} <col:8> col:8{{( imported)?}} implicit 'V'
@@ -94,7 +94,7 @@ template <typename... Ts> void test(Ts... a) {
 // CHECK-NEXT:    | | | |-MoveConstructor exists simple trivial needs_implicit
 // CHECK-NEXT:    | | | |-CopyAssignment trivial has_const_param needs_implicit implicit_has_const_param
 // CHECK-NEXT:    | | | |-MoveAssignment
-// CHECK-NEXT:    | | | `-Destructor simple irrelevant trivial needs_implicit
+// CHECK-NEXT:    | | | `-Destructor simple irrelevant trivial{{( maybe_constexpr)?}} needs_implicit
 // CHECK-NEXT:    | | |-CXXMethodDecl {{.*}} <col:6, col:9> col:3{{( imported)?}} operator() 'auto () const' inline
 // CHECK-NEXT:    | | | `-CompoundStmt {{.*}} <col:8, col:9>
 // CHECK-NEXT:    | | |-CXXConversionDecl {{.*}} <col:3, col:9> col:3{{( imported)?}} implicit constexpr operator auto (*)() 'auto (*() const noexcept)()' inline
@@ -108,7 +108,7 @@ template <typename... Ts> void test(Ts... a) {
 // CHECK-NEXT:    | | | |-MoveConstructor exists simple trivial needs_implicit
 // CHECK-NEXT:    | | | |-CopyAssignment trivial has_const_param needs_implicit implicit_has_const_param
 // CHECK-NEXT:    | | | |-MoveAssignment
-// CHECK-NEXT:    | | | `-Destructor simple irrelevant trivial needs_implicit
+// CHECK-NEXT:    | | | `-Destructor simple irrelevant trivial{{( maybe_constexpr)?}} needs_implicit
 // CHECK-NEXT:    | | |-CXXMethodDecl {{.*}} <col:16, col:19> col:3{{( imported)?}} operator() 'auto (int, ...) const' inline
 // CHECK-NEXT:    | | | |-ParmVarDecl {{.*}} <col:6, col:10> col:10{{( imported)?}} a 'int'
 // CHECK-NEXT:    | | | `-CompoundStmt {{.*}} <col:18, col:19>
@@ -124,7 +124,7 @@ template <typename... Ts> void test(Ts... a) {
 // CHECK-NEXT:    | | | |-MoveConstructor exists simple trivial needs_implicit
 // CHECK-NEXT:    | | | |-CopyAssignment trivial has_const_param needs_implicit implicit_has_const_param
 // CHECK-NEXT:    | | | |-MoveAssignment
-// CHECK-NEXT:    | | | `-Destructor simple irrelevant trivial needs_implicit
+// CHECK-NEXT:    | | | `-Destructor simple irrelevant trivial{{( maybe_constexpr)?}} needs_implicit
 // CHECK-NEXT:    | | |-CXXMethodDecl {{.*}} <col:8, col:11> col:3{{( imported)?}} operator() 'auto () const -> auto' inline
 // CHECK-NEXT:    | | | `-CompoundStmt {{.*}} <col:10, col:11>
 // CHECK-NEXT:    | | `-FieldDecl {{.*}} <col:4> col:4{{( imported)?}} implicit 'Ts...'
@@ -139,7 +139,7 @@ template <typename... Ts> void test(Ts... a) {
 // CHECK-NEXT:    | | | |-MoveConstructor exists simple trivial needs_implicit
 // CHECK-NEXT:    | | | |-CopyAssignment trivial has_const_param needs_implicit implicit_has_const_param
 // CHECK-NEXT:    | | | |-MoveAssignment
-// CHECK-NEXT:    | | | `-Destructor simple irrelevant trivial needs_implicit
+// CHECK-NEXT:    | | | `-Destructor simple irrelevant trivial{{( maybe_constexpr)?}} needs_implicit
 // CHECK-NEXT:    | | `-CXXMethodDecl {{.*}} <col:5, col:8> col:3{{( imported)?}} operator() 'auto () const -> auto' inline
 // CHECK-NEXT:    | |   `-CompoundStmt {{.*}} <col:7, col:8>
 // CHECK-NEXT:    | `-CompoundStmt {{.*}} <col:7, col:8>
@@ -151,7 +151,7 @@ template <typename... Ts> void test(Ts... a) {
 // CHECK-NEXT:    | | | |-MoveConstructor exists simple trivial needs_implicit
 // CHECK-NEXT:    | | | |-CopyAssignment trivial has_const_param needs_implicit implicit_has_const_param
 // CHECK-NEXT:    | | | |-MoveAssignment
-// CHECK-NEXT:    | | | `-Destructor simple irrelevant trivial needs_implicit
+// CHECK-NEXT:    | | | `-Destructor simple irrelevant trivial{{( maybe_constexpr)?}} needs_implicit
 // CHECK-NEXT:    | | `-CXXMethodDecl {{.*}} <col:5, col:19> col:3{{( imported)?}} operator() 'auto () const -> auto' inline
 // CHECK-NEXT:    | |   `-CompoundStmt {{.*}} <col:7, col:19>
 // CHECK-NEXT:    | |     `-ReturnStmt {{.*}} <col:9, col:16>
@@ -167,7 +167,7 @@ template <typename... Ts> void test(Ts... a) {
 // CHECK-NEXT:    | | | |-MoveConstructor exists simple trivial needs_implicit
 // CHECK-NEXT:    | | | |-CopyAssignment trivial has_const_param needs_implicit implicit_has_const_param
 // CHECK-NEXT:    | | | |-MoveAssignment
-// CHECK-NEXT:    | | | `-Destructor simple irrelevant trivial needs_implicit
+// CHECK-NEXT:    | | | `-Destructor simple irrelevant trivial{{( maybe_constexpr)?}} needs_implicit
 // CHECK-NEXT:    | | `-CXXMethodDecl {{.*}} <col:5, col:8> col:3{{( imported)?}} operator() 'auto () const -> auto' inline
 // CHECK-NEXT:    | |   `-CompoundStmt {{.*}} <col:7, col:8>
 // CHECK-NEXT:    | `-CompoundStmt {{.*}} <col:7, col:8>
@@ -179,7 +179,7 @@ template <typename... Ts> void test(Ts... a) {
 // CHECK-NEXT:    | | | |-MoveConstructor exists simple trivial needs_implicit
 // CHECK-NEXT:    | | | |-CopyAssignment trivial has_const_param needs_implicit implicit_has_const_param
 // CHECK-NEXT:    | | | |-MoveAssignment
-// CHECK-NEXT:    | | | `-Destructor simple irrelevant trivial needs_implicit
+// CHECK-NEXT:    | | | `-Destructor simple irrelevant trivial{{( maybe_constexpr)?}} needs_implicit
 // CHECK-NEXT:    | | `-CXXMethodDecl {{.*}} <col:5, col:19> col:3{{( imported)?}} operator() 'auto () const -> auto' inline
 // CHECK-NEXT:    | |   `-CompoundStmt {{.*}} <col:7, col:19>
 // CHECK-NEXT:    | |     `-ReturnStmt {{.*}} <col:9, col:16>
@@ -195,7 +195,7 @@ template <typename... Ts> void test(Ts... a) {
 // CHECK-NEXT:    | | | |-MoveConstructor exists simple trivial needs_implicit
 // CHECK-NEXT:    | | | |-CopyAssignment trivial has_const_param needs_implicit implicit_has_const_param
 // CHECK-NEXT:    | | | |-MoveAssignment
-// CHECK-NEXT:    | | | `-Destructor simple irrelevant trivial needs_implicit
+// CHECK-NEXT:    | | | `-Destructor simple irrelevant trivial{{( maybe_constexpr)?}} needs_implicit
 // CHECK-NEXT:    | | |-CXXMethodDecl {{.*}} <col:9, col:27> col:3{{( imported)?}} operator() 'auto () const -> auto' inline
 // CHECK-NEXT:    | | | `-CompoundStmt {{.*}} <col:11, col:27>
 // CHECK-NEXT:    | | |   `-ReturnStmt {{.*}} <col:13, col:24>
@@ -224,7 +224,7 @@ template <typename... Ts> void test(Ts... a) {
 // CHECK-NEXT:    | | | |-MoveConstructor exists simple trivial needs_implicit
 // CHECK-NEXT:    | | | |-CopyAssignment trivial has_const_param needs_implicit implicit_has_const_param
 // CHECK-NEXT:    | | | |-MoveAssignment
-// CHECK-NEXT:    | | | `-Destructor simple irrelevant trivial needs_implicit
+// CHECK-NEXT:    | | | `-Destructor simple irrelevant trivial{{( maybe_constexpr)?}} needs_implicit
 // CHECK-NEXT:    | | |-CXXMethodDecl {{.*}} <col:16, col:19> col:3{{( imported)?}} operator() 'auto () const -> auto' inline
 // CHECK-NEXT:    | | | `-CompoundStmt {{.*}} <col:18, col:19>
 // CHECK-NEXT:    | | |-FieldDecl {{.*}} <col:4> col:4{{( imported)?}} implicit 'Ts...'
@@ -241,7 +241,7 @@ template <typename... Ts> void test(Ts... a) {
 // CHECK-NEXT:    | | | |-MoveConstructor exists simple trivial needs_implicit
 // CHECK-NEXT:    | | | |-CopyAssignment trivial has_const_param needs_implicit implicit_has_const_param
 // CHECK-NEXT:    | | | |-MoveAssignment
-// CHECK-NEXT:    | | | `-Destructor simple irrelevant trivial needs_implicit
+// CHECK-NEXT:    | | | `-Destructor simple irrelevant trivial{{( maybe_constexpr)?}} needs_implicit
 // CHECK-NEXT:    | | |-CXXMethodDecl {{.*}} <col:8, col:19> col:3{{( imported)?}} constexpr operator() 'auto () const' inline
 // CHECK-NEXT:    | | | `-CompoundStmt {{.*}} <col:18, col:19>
 // CHECK-NEXT:    | | |-CXXConversionDecl {{.*}} <col:3, col:19> col:3{{( imported)?}} implicit constexpr operator auto (*)() 'auto (*() const noexcept)()' inline
@@ -255,7 +255,7 @@ template <typename... Ts> void test(Ts... a) {
 // CHECK-NEXT:    | | | |-MoveConstructor exists simple trivial needs_implicit
 // CHECK-NEXT:    | | | |-CopyAssignment trivial has_const_param needs_implicit implicit_has_const_param
 // CHECK-NEXT:    | | | |-MoveAssignment
-// CHECK-NEXT:    | | | `-Destructor simple irrelevant trivial needs_implicit
+// CHECK-NEXT:    | | | `-Destructor simple irrelevant trivial{{( maybe_constexpr)?}} needs_implicit
 // CHECK-NEXT:    | | |-CXXMethodDecl {{.*}} <col:8, col:17> col:3{{( imported)?}} operator() 'auto ()' inline
 // CHECK-NEXT:    | | | `-CompoundStmt {{.*}} <col:16, col:17>
 // CHECK-NEXT:    | | |-CXXConversionDecl {{.*}} <col:3, col:17> col:3{{( imported)?}} implicit constexpr operator auto (*)() 'auto (*() const noexcept)()' inline
@@ -269,7 +269,7 @@ template <typename... Ts> void test(Ts... a) {
 // CHECK-NEXT:    | | | |-MoveConstructor exists simple trivial needs_implicit
 // CHECK-NEXT:    | | | |-CopyAssignment trivial has_const_param needs_implicit implicit_has_const_param
 // CHECK-NEXT:    | | | |-MoveAssignment
-// CHECK-NEXT:    | | | `-Destructor simple irrelevant trivial needs_implicit
+// CHECK-NEXT:    | | | `-Destructor simple irrelevant trivial{{( maybe_constexpr)?}} needs_implicit
 // CHECK-NEXT:    | | |-CXXMethodDecl {{.*}} <col:8, col:18> col:3{{( imported)?}} operator() 'auto () const noexcept' inline
 // CHECK-NEXT:    | | | `-CompoundStmt {{.*}} <col:17, col:18>
 // CHECK-NEXT:    | | |-CXXConversionDecl {{.*}} <col:3, col:18> col:3{{( imported)?}} implicit constexpr operator auto (*)() noexcept 'auto (*() const noexcept)() noexcept' inline
@@ -283,7 +283,7 @@ template <typename... Ts> void test(Ts... a) {
 // CHECK-NEXT:      | | |-MoveConstructor exists simple trivial needs_implicit
 // CHECK-NEXT:      | | |-CopyAssignment trivial has_const_param needs_implicit implicit_has_const_param
 // CHECK-NEXT:      | | |-MoveAssignment
-// CHECK-NEXT:      | | `-Destructor simple irrelevant trivial needs_implicit
+// CHECK-NEXT:      | | `-Destructor simple irrelevant trivial{{( maybe_constexpr)?}} needs_implicit
 // CHECK-NEXT:      | |-CXXMethodDecl {{.*}} <col:11, col:27> col:3{{( imported)?}} operator() 'auto () const -> int' inline
 // CHECK-NEXT:      | | `-CompoundStmt {{.*}} <col:15, col:27>
 // CHECK-NEXT:      | |   `-ReturnStmt {{.*}} <col:17, col:24>

diff  --git a/clang/test/AST/ast-dump-records.cpp b/clang/test/AST/ast-dump-records.cpp
index cb7ac8320431..cdaa2ef16eba 100644
--- a/clang/test/AST/ast-dump-records.cpp
+++ b/clang/test/AST/ast-dump-records.cpp
@@ -22,7 +22,7 @@ struct A {
   // CHECK-NEXT: MoveConstructor exists simple trivial needs_implicit
   // CHECK-NEXT: CopyAssignment simple trivial has_const_param needs_implicit implicit_has_const_param
   // CHECK-NEXT: MoveAssignment exists simple trivial needs_implicit
-  // CHECK-NEXT: Destructor simple irrelevant trivial needs_implicit
+  // CHECK-NEXT: Destructor simple irrelevant trivial{{( maybe_constexpr)?}} needs_implicit
 
   // CHECK-NEXT: CXXRecordDecl 0x{{[^ ]*}} <col:1, col:8> col:8 implicit struct A
   int a;
@@ -57,7 +57,7 @@ struct C {
   // CHECK-NEXT: MoveConstructor exists simple trivial needs_implicit
   // CHECK-NEXT: CopyAssignment simple trivial has_const_param needs_implicit implicit_has_const_param
   // CHECK-NEXT: MoveAssignment exists simple trivial needs_implicit
-  // CHECK-NEXT: Destructor simple irrelevant trivial needs_implicit
+  // CHECK-NEXT: Destructor simple irrelevant trivial{{( maybe_constexpr)?}} needs_implicit
 
   // CHECK-NEXT: CXXRecordDecl 0x{{[^ ]*}} <col:1, col:8> col:8 implicit struct C
   struct {
@@ -68,7 +68,7 @@ struct C {
     // CHECK-NEXT: MoveConstructor exists simple trivial needs_implicit
     // CHECK-NEXT: CopyAssignment simple trivial has_const_param needs_implicit implicit_has_const_param
     // CHECK-NEXT: MoveAssignment exists simple trivial needs_implicit
-    // CHECK-NEXT: Destructor simple irrelevant trivial needs_implicit
+    // CHECK-NEXT: Destructor simple irrelevant trivial{{( maybe_constexpr)?}} needs_implicit
     int a;
     // CHECK-NEXT: FieldDecl 0x{{[^ ]*}} <line:[[@LINE-1]]:5, col:9> col:9 a 'int'
   } b;
@@ -82,7 +82,7 @@ struct C {
     // CHECK-NEXT: MoveConstructor exists simple trivial needs_implicit
     // CHECK-NEXT: CopyAssignment simple trivial has_const_param needs_implicit implicit_has_const_param
     // CHECK-NEXT: MoveAssignment exists simple trivial needs_implicit
-    // CHECK-NEXT: Destructor simple irrelevant trivial needs_implicit
+    // CHECK-NEXT: Destructor simple irrelevant trivial{{( maybe_constexpr)?}} needs_implicit
     int c;
     // CHECK-NEXT: FieldDecl 0x{{[^ ]*}} <line:[[@LINE-1]]:5, col:9> col:9 c 'int'
     float d;
@@ -104,7 +104,7 @@ struct C {
     // CHECK-NEXT: MoveConstructor exists simple trivial needs_implicit
     // CHECK-NEXT: CopyAssignment simple trivial has_const_param needs_implicit implicit_has_const_param
     // CHECK-NEXT: MoveAssignment exists simple trivial needs_implicit
-    // CHECK-NEXT: Destructor simple irrelevant trivial needs_implicit
+    // CHECK-NEXT: Destructor simple irrelevant trivial{{( maybe_constexpr)?}} needs_implicit
     int e, f;
     // CHECK-NEXT: FieldDecl 0x{{[^ ]*}} <line:[[@LINE-1]]:5, col:9> col:9 e 'int'
     // CHECK-NEXT: FieldDecl 0x{{[^ ]*}} <col:5, col:12> col:12 f 'int'
@@ -126,7 +126,7 @@ struct D {
   // CHECK-NEXT: MoveConstructor exists simple trivial needs_implicit
   // CHECK-NEXT: CopyAssignment simple trivial has_const_param needs_implicit implicit_has_const_param
   // CHECK-NEXT: MoveAssignment exists simple trivial needs_implicit
-  // CHECK-NEXT: Destructor simple irrelevant trivial needs_implicit
+  // CHECK-NEXT: Destructor simple irrelevant trivial{{( maybe_constexpr)?}} needs_implicit
 
   // CHECK-NEXT: CXXRecordDecl 0x{{[^ ]*}} <col:1, col:8> col:8 implicit struct D
   int a;
@@ -151,7 +151,7 @@ union E {
   // CHECK-NEXT: MoveConstructor exists simple trivial needs_implicit
   // CHECK-NEXT: CopyAssignment simple trivial has_const_param needs_implicit implicit_has_const_param
   // CHECK-NEXT: MoveAssignment exists simple trivial needs_implicit
-  // CHECK-NEXT: Destructor simple irrelevant trivial needs_implicit
+  // CHECK-NEXT: Destructor simple irrelevant trivial{{( maybe_constexpr)?}} needs_implicit
 
   // CHECK-NEXT: CXXRecordDecl 0x{{[^ ]*}} <col:1, col:7> col:7 implicit union E
   int a;
@@ -186,7 +186,7 @@ union G {
   // CHECK-NEXT: MoveConstructor exists simple trivial needs_implicit
   // CHECK-NEXT: CopyAssignment simple trivial has_const_param needs_implicit implicit_has_const_param
   // CHECK-NEXT: MoveAssignment exists simple trivial needs_implicit
-  // CHECK-NEXT: Destructor simple irrelevant trivial needs_implicit
+  // CHECK-NEXT: Destructor simple irrelevant trivial{{( maybe_constexpr)?}} needs_implicit
 
   // CHECK-NEXT: CXXRecordDecl 0x{{[^ ]*}} <col:1, col:7> col:7 implicit union G
   struct {
@@ -197,7 +197,7 @@ union G {
     // CHECK-NEXT: MoveConstructor exists simple trivial needs_implicit
     // CHECK-NEXT: CopyAssignment simple trivial has_const_param needs_implicit implicit_has_const_param
     // CHECK-NEXT: MoveAssignment exists simple trivial needs_implicit
-    // CHECK-NEXT: Destructor simple irrelevant trivial needs_implicit
+    // CHECK-NEXT: Destructor simple irrelevant trivial{{( maybe_constexpr)?}} needs_implicit
 
     int a;
     // CHECK-NEXT: FieldDecl 0x{{[^ ]*}} <line:[[@LINE-1]]:5, col:9> col:9 a 'int'
@@ -214,7 +214,7 @@ union G {
     // CHECK-NEXT: MoveConstructor exists simple trivial needs_implicit
     // CHECK-NEXT: CopyAssignment simple trivial has_const_param needs_implicit implicit_has_const_param
     // CHECK-NEXT: MoveAssignment exists simple trivial needs_implicit
-    // CHECK-NEXT: Destructor simple irrelevant trivial needs_implicit
+    // CHECK-NEXT: Destructor simple irrelevant trivial{{( maybe_constexpr)?}} needs_implicit
 
     int c;
     // CHECK-NEXT: FieldDecl 0x{{[^ ]*}} <line:[[@LINE-1]]:5, col:9> col:9 c 'int'
@@ -237,7 +237,7 @@ union G {
     // CHECK-NEXT: MoveConstructor exists simple trivial needs_implicit
     // CHECK-NEXT: CopyAssignment simple trivial has_const_param needs_implicit implicit_has_const_param
     // CHECK-NEXT: MoveAssignment exists simple trivial needs_implicit
-    // CHECK-NEXT: Destructor simple irrelevant trivial needs_implicit
+    // CHECK-NEXT: Destructor simple irrelevant trivial{{( maybe_constexpr)?}} needs_implicit
 
     int e, f;
     // CHECK-NEXT: FieldDecl 0x{{[^ ]*}} <line:[[@LINE-1]]:5, col:9> col:9 e 'int'

diff  --git a/clang/unittests/AST/ASTDumpTest.cpp b/clang/unittests/AST/ASTDumpTest.cpp
new file mode 100644
index 000000000000..45884dfd11d0
--- /dev/null
+++ b/clang/unittests/AST/ASTDumpTest.cpp
@@ -0,0 +1,140 @@
+//===- unittests/AST/ASTDumpTest.cpp --- Declaration tests ----------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Tests Decl::dump().
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Basic/Builtins.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/SourceManager.h"
+#include "gtest/gtest.h"
+
+using namespace clang;
+
+namespace clang {
+namespace ast {
+
+namespace {
+/// An ExternalASTSource that asserts if it is queried for information about
+/// any declaration.
+class TrappingExternalASTSource : public ExternalASTSource {
+  ~TrappingExternalASTSource() override = default;
+  bool FindExternalVisibleDeclsByName(const DeclContext *,
+                                      DeclarationName) override {
+    assert(false && "Unexpected call to FindExternalVisibleDeclsByName");
+    return true;
+  }
+
+  void FindExternalLexicalDecls(const DeclContext *,
+                                llvm::function_ref<bool(Decl::Kind)>,
+                                SmallVectorImpl<Decl *> &) override {
+    assert(false && "Unexpected call to FindExternalLexicalDecls");
+  }
+
+  void completeVisibleDeclsMap(const DeclContext *) override {
+    assert(false && "Unexpected call to completeVisibleDeclsMap");
+  }
+
+  void CompleteRedeclChain(const Decl *) override {
+    assert(false && "Unexpected call to CompleteRedeclChain");
+  }
+
+  void CompleteType(TagDecl *) override {
+    assert(false && "Unexpected call to CompleteType(Tag Decl*)");
+  }
+
+  void CompleteType(ObjCInterfaceDecl *) override {
+    assert(false && "Unexpected call to CompleteType(ObjCInterfaceDecl *)");
+  }
+};
+
+/// Tests that Decl::dump doesn't load additional declarations from the
+/// ExternalASTSource.
+class ExternalASTSourceDumpTest : public ::testing::Test {
+protected:
+  ExternalASTSourceDumpTest()
+      : FileMgr(FileMgrOpts), DiagID(new DiagnosticIDs()),
+        Diags(DiagID, new DiagnosticOptions, new IgnoringDiagConsumer()),
+        SourceMgr(Diags, FileMgr), Idents(LangOpts, nullptr),
+        Ctxt(LangOpts, SourceMgr, Idents, Sels, Builtins) {
+    Ctxt.setExternalSource(new TrappingExternalASTSource());
+  }
+
+  FileSystemOptions FileMgrOpts;
+  FileManager FileMgr;
+  IntrusiveRefCntPtr<DiagnosticIDs> DiagID;
+  DiagnosticsEngine Diags;
+  SourceManager SourceMgr;
+  LangOptions LangOpts;
+  IdentifierTable Idents;
+  SelectorTable Sels;
+  Builtin::Context Builtins;
+  ASTContext Ctxt;
+};
+} // unnamed namespace
+
+/// Set all flags that activate queries to the ExternalASTSource.
+static void setExternalStorageFlags(DeclContext *DC) {
+  DC->setHasExternalLexicalStorage();
+  DC->setHasExternalVisibleStorage();
+  DC->setMustBuildLookupTable();
+}
+
+/// Dumps the given Decl.
+static void dumpDecl(Decl *D) {
+  // Try dumping the decl which shouldn't trigger any calls to the
+  // ExternalASTSource.
+
+  std::string Out;
+  llvm::raw_string_ostream OS(Out);
+  D->dump(OS);
+}
+
+TEST_F(ExternalASTSourceDumpTest, DumpObjCInterfaceDecl) {
+  // Define an Objective-C interface.
+  ObjCInterfaceDecl *I = ObjCInterfaceDecl::Create(
+      Ctxt, Ctxt.getTranslationUnitDecl(), SourceLocation(),
+      &Ctxt.Idents.get("c"), nullptr, nullptr);
+  Ctxt.getTranslationUnitDecl()->addDecl(I);
+
+  setExternalStorageFlags(I);
+  dumpDecl(I);
+}
+
+TEST_F(ExternalASTSourceDumpTest, DumpRecordDecl) {
+  // Define a struct.
+  RecordDecl *R = RecordDecl::Create(
+      Ctxt, TagDecl::TagKind::TTK_Class, Ctxt.getTranslationUnitDecl(),
+      SourceLocation(), SourceLocation(), &Ctxt.Idents.get("c"));
+  R->startDefinition();
+  R->completeDefinition();
+  Ctxt.getTranslationUnitDecl()->addDecl(R);
+
+  setExternalStorageFlags(R);
+  dumpDecl(R);
+}
+
+TEST_F(ExternalASTSourceDumpTest, DumpCXXRecordDecl) {
+  // Define a class.
+  CXXRecordDecl *R = CXXRecordDecl::Create(
+      Ctxt, TagDecl::TagKind::TTK_Class, Ctxt.getTranslationUnitDecl(),
+      SourceLocation(), SourceLocation(), &Ctxt.Idents.get("c"));
+  R->startDefinition();
+  R->completeDefinition();
+  Ctxt.getTranslationUnitDecl()->addDecl(R);
+
+  setExternalStorageFlags(R);
+  dumpDecl(R);
+}
+
+} // end namespace ast
+} // end namespace clang

diff  --git a/clang/unittests/AST/CMakeLists.txt b/clang/unittests/AST/CMakeLists.txt
index 2d5d0172afed..9e0a33fd762f 100644
--- a/clang/unittests/AST/CMakeLists.txt
+++ b/clang/unittests/AST/CMakeLists.txt
@@ -6,6 +6,7 @@ set(LLVM_LINK_COMPONENTS
 
 add_clang_unittest(ASTTests
   ASTContextParentMapTest.cpp
+  ASTDumpTest.cpp
   ASTImporterFixtures.cpp
   ASTImporterTest.cpp
   ASTImporterGenericRedeclTest.cpp


        


More information about the cfe-commits mailing list