Skip to content

Commit

Permalink
Handle variable templates in DeclUnloader
Browse files Browse the repository at this point in the history
Fixes #13815
  • Loading branch information
hahnjo authored and jenkins committed Nov 30, 2023
1 parent df71846 commit 5cf51d5
Show file tree
Hide file tree
Showing 3 changed files with 128 additions and 0 deletions.
68 changes: 68 additions & 0 deletions lib/Interpreter/DeclUnloader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,37 @@ namespace {
removeSpecializationImpl(specs, spec);
}
};

// A template specialization is attached to the list of specialization of
// the templated variable.
//
class VarTemplateDeclExt : public VarTemplateDecl {
public:
static void removeSpecialization(VarTemplateDecl* self,
VarTemplateSpecializationDecl* spec) {
assert(!isa<VarTemplatePartialSpecializationDecl>(spec) &&
"Use removePartialSpecialization");
assert(self && spec && "Cannot be null!");
assert(spec == spec->getCanonicalDecl() &&
"Not the canonical specialization!?");

auto* This = static_cast<VarTemplateDeclExt*>(self);
auto& specs = This->getCommonPtr()->Specializations;
removeSpecializationImpl(specs, spec);
}

static void
removePartialSpecialization(VarTemplateDecl* self,
VarTemplatePartialSpecializationDecl* spec) {
assert(self && spec && "Cannot be null!");
assert(spec == spec->getCanonicalDecl() &&
"Not the canonical specialization!?");

auto* This = static_cast<VarTemplateDeclExt*>(self);
auto& specs = This->getPartialSpecializations();
removeSpecializationImpl(specs, spec);
}
};
} // end anonymous namespace

namespace cling {
Expand Down Expand Up @@ -1017,4 +1048,41 @@ namespace cling {
ClassTemplateSpecializationDecl* CTSD) {
return VisitClassTemplateSpecializationDecl(CTSD, /*RemoveSpec=*/true);
}

bool DeclUnloader::VisitVarTemplateDecl(VarTemplateDecl* VTD) {
// VarTemplateDecl: TemplateDecl, Redeclarable
bool Successful = true;
// Remove specializations, but do not invalidate the iterator!
for (VarTemplateDecl::spec_iterator I = VTD->loaded_spec_begin(),
E = VTD->loaded_spec_end();
I != E; ++I)
Successful &=
VisitVarTemplateSpecializationDecl(*I, /*RemoveSpec=*/false);

Successful &= VisitRedeclarableTemplateDecl(VTD);
Successful &= Visit(VTD->getTemplatedDecl());
return Successful;
}

bool DeclUnloader::VisitVarTemplateSpecializationDecl(
VarTemplateSpecializationDecl* VTSD, bool RemoveSpec) {
// VarTemplateSpecializationDecl: VarDecl, FoldingSet
bool Successful = VisitVarDecl(VTSD);
if (RemoveSpec) {
VarTemplateSpecializationDecl* CanonVTSD =
static_cast<VarTemplateSpecializationDecl*>(VTSD->getCanonicalDecl());
if (auto D = dyn_cast<VarTemplatePartialSpecializationDecl>(CanonVTSD))
VarTemplateDeclExt::removePartialSpecialization(
D->getSpecializedTemplate(), D);
else
VarTemplateDeclExt::removeSpecialization(VTSD->getSpecializedTemplate(),
CanonVTSD);
}
return Successful;
}

bool DeclUnloader::VisitVarTemplateSpecializationDecl(
VarTemplateSpecializationDecl* VTSD) {
return VisitVarTemplateSpecializationDecl(VTSD, /*RemoveSpec=*/true);
}
} // end namespace cling
28 changes: 28 additions & 0 deletions lib/Interpreter/DeclUnloader.h
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,34 @@ namespace cling {
bool VisitClassTemplateSpecializationDecl(
clang::ClassTemplateSpecializationDecl* CTSD);

///\brief Removes a var template declaration from clang's internal
/// structures.
/// @param[in] VTD - The declaration to be removed.
///
///\returns true on success.
///
bool VisitVarTemplateDecl(clang::VarTemplateDecl* VTD);

///\brief Removes a var template specialization declaration from clang's
/// internal structures.
/// @param[in] CTSD - The declaration to be removed.
/// @param[in] RemoveSpec - Whether to remove the specialization from its
/// parent.
///
///\returns true on success.
///
bool VisitVarTemplateSpecializationDecl(
clang::VarTemplateSpecializationDecl* VTSD, bool RemoveSpec);

///\brief Removes a var template specialization declaration from clang's
/// internal structures.
/// @param[in] CTSD - The declaration to be removed.
///
///\returns true on success.
///
bool VisitVarTemplateSpecializationDecl(
clang::VarTemplateSpecializationDecl* VTSD);

///@}

void MaybeRemoveDeclFromModule(clang::GlobalDecl& GD) const;
Expand Down
32 changes: 32 additions & 0 deletions test/ErrorRecovery/IncompleteType.C
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
//
// This file is dual-licensed: you can choose to license it under the University
// of Illinois Open Source License or the GNU Lesser General Public License. See
// LICENSE.TXT for details.
//------------------------------------------------------------------------------

// RUN: cat %s | %cling 2>&1 | FileCheck %s

#include <type_traits>

struct A { int v; };
std::is_default_constructible_v<A>
// CHECK: (const bool) true

struct B;
std::is_default_constructible_v<B>
// CHECK: incomplete type 'B'
struct B { int v; };
std::is_default_constructible_v<B>
// CHECK: (const bool) true

template <typename T> struct C;
template <> struct C<int>;
std::is_default_constructible_v<C<int>>
// CHECK: incomplete type 'C<int>'
template <> struct C<int> { int v; };
std::is_default_constructible_v<C<int>>
// CHECK: (const bool) true

.q

0 comments on commit 5cf51d5

Please sign in to comment.