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 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits