Skip to content

Commit 4878337

Browse files
committed
Revert "[Clang][Sema] Handle invalid variable template specialization whose type depends on itself (llvm#134522)"
This reverts commit 91f1830.
1 parent f1043b1 commit 4878337

File tree

10 files changed

+85
-170
lines changed

10 files changed

+85
-170
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -684,8 +684,6 @@ Bug Fixes to C++ Support
684684
- Fixed an assertion when trying to constant-fold various builtins when the argument
685685
referred to a reference to an incomplete type. (#GH129397)
686686
- Fixed a crash when a cast involved a parenthesized aggregate initialization in dependent context. (#GH72880)
687-
- No longer crashes when instantiating invalid variable template specialization
688-
whose type depends on itself. (#GH51347), (#GH55872)
689687
- Improved parser recovery of invalid requirement expressions. In turn, this
690688
fixes crashes from follow-on processing of the invalid requirement. (#GH138820)
691689
- Fixed the handling of pack indexing types in the constraints of a member function redeclaration. (#GH138255)

clang/include/clang/AST/ASTContext.h

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2971,11 +2971,6 @@ class ASTContext : public RefCountedBase<ASTContext> {
29712971
TemplateTemplateParmDecl *insertCanonicalTemplateTemplateParmDeclInternal(
29722972
TemplateTemplateParmDecl *CanonTTP) const;
29732973

2974-
/// Determine whether the given template arguments \p Arg1 and \p Arg2 are
2975-
/// equivalent.
2976-
bool isSameTemplateArgument(const TemplateArgument &Arg1,
2977-
const TemplateArgument &Arg2) const;
2978-
29792974
/// Type Query functions. If the type is an instance of the specified class,
29802975
/// return the Type pointer for the underlying maximally pretty type. This
29812976
/// is a member of ASTContext because this may need to do some amount of

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2531,14 +2531,9 @@ def note_implicit_deduction_guide : Note<"implicit deduction guide declared as '
25312531
def warn_cxx98_compat_auto_type_specifier : Warning<
25322532
"'auto' type specifier is incompatible with C++98">,
25332533
InGroup<CXX98Compat>, DefaultIgnore;
2534-
def err_auto_variable_cannot_appear_in_own_initializer
2535-
: Error<
2536-
"%enum_select<ParsingInitFor>{%Var{variable}|"
2537-
"%VarTemplate{variable template}|"
2538-
"%VarTemplatePartialSpec{variable template partial specialization}|"
2539-
"%VarTemplateExplicitSpec{variable template explicit "
2540-
"specialization}}0 %1 "
2541-
"declared with deduced type %2 cannot appear in its own initializer">;
2534+
def err_auto_variable_cannot_appear_in_own_initializer : Error<
2535+
"variable %0 declared with deduced type %1 "
2536+
"cannot appear in its own initializer">;
25422537
def err_binding_cannot_appear_in_own_initializer : Error<
25432538
"binding %0 cannot appear in the initializer of its own "
25442539
"decomposition declaration">;
@@ -5312,9 +5307,6 @@ def err_template_member_noparams : Error<
53125307
"extraneous 'template<>' in declaration of member %0">;
53135308
def err_template_tag_noparams : Error<
53145309
"extraneous 'template<>' in declaration of %0 %1">;
5315-
def err_var_template_spec_type_depends_on_self : Error<
5316-
"the type of variable template specialization %0 declared with deduced type "
5317-
"%1 depends on itself">;
53185310

53195311
def warn_unqualified_call_to_std_cast_function : Warning<
53205312
"unqualified call to '%0'">, InGroup<DiagGroup<"unqualified-std-cast-call">>;

clang/lib/AST/ASTContext.cpp

Lines changed: 0 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -7666,55 +7666,6 @@ ASTContext::getCanonicalTemplateArgument(const TemplateArgument &Arg) const {
76667666
llvm_unreachable("Unhandled template argument kind");
76677667
}
76687668

7669-
bool ASTContext::isSameTemplateArgument(const TemplateArgument &Arg1,
7670-
const TemplateArgument &Arg2) const {
7671-
if (Arg1.getKind() != Arg2.getKind())
7672-
return false;
7673-
7674-
switch (Arg1.getKind()) {
7675-
case TemplateArgument::Null:
7676-
llvm_unreachable("Comparing NULL template argument");
7677-
7678-
case TemplateArgument::Type:
7679-
return hasSameType(Arg1.getAsType(), Arg2.getAsType());
7680-
7681-
case TemplateArgument::Declaration:
7682-
return Arg1.getAsDecl()->getUnderlyingDecl()->getCanonicalDecl() ==
7683-
Arg2.getAsDecl()->getUnderlyingDecl()->getCanonicalDecl();
7684-
7685-
case TemplateArgument::NullPtr:
7686-
return hasSameType(Arg1.getNullPtrType(), Arg2.getNullPtrType());
7687-
7688-
case TemplateArgument::Template:
7689-
case TemplateArgument::TemplateExpansion:
7690-
return getCanonicalTemplateName(Arg1.getAsTemplateOrTemplatePattern()) ==
7691-
getCanonicalTemplateName(Arg2.getAsTemplateOrTemplatePattern());
7692-
7693-
case TemplateArgument::Integral:
7694-
return llvm::APSInt::isSameValue(Arg1.getAsIntegral(),
7695-
Arg2.getAsIntegral());
7696-
7697-
case TemplateArgument::StructuralValue:
7698-
return Arg1.structurallyEquals(Arg2);
7699-
7700-
case TemplateArgument::Expression: {
7701-
llvm::FoldingSetNodeID ID1, ID2;
7702-
Arg1.getAsExpr()->Profile(ID1, *this, /*Canonical=*/true);
7703-
Arg2.getAsExpr()->Profile(ID2, *this, /*Canonical=*/true);
7704-
return ID1 == ID2;
7705-
}
7706-
7707-
case TemplateArgument::Pack:
7708-
return llvm::equal(
7709-
Arg1.getPackAsArray(), Arg2.getPackAsArray(),
7710-
[&](const TemplateArgument &Arg1, const TemplateArgument &Arg2) {
7711-
return isSameTemplateArgument(Arg1, Arg2);
7712-
});
7713-
}
7714-
7715-
llvm_unreachable("Unhandled template argument kind");
7716-
}
7717-
77187669
NestedNameSpecifier *
77197670
ASTContext::getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS) const {
77207671
if (!NNS)

clang/lib/Sema/SemaExpr.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -251,8 +251,7 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, ArrayRef<SourceLocation> Locs,
251251
<< D->getDeclName();
252252
} else {
253253
Diag(Loc, diag::err_auto_variable_cannot_appear_in_own_initializer)
254-
<< diag::ParsingInitFor::Var << D->getDeclName()
255-
<< cast<VarDecl>(D)->getType();
254+
<< D->getDeclName() << cast<VarDecl>(D)->getType();
256255
}
257256
return true;
258257
}

clang/lib/Sema/SemaTemplate.cpp

Lines changed: 1 addition & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -4373,64 +4373,15 @@ Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc,
43734373
// Produce a placeholder value if the specialization is dependent.
43744374
if (Template->getDeclContext()->isDependentContext() ||
43754375
TemplateSpecializationType::anyDependentTemplateArguments(
4376-
TemplateArgs, CTAI.CanonicalConverted)) {
4377-
if (ParsingInitForAutoVars.empty())
4378-
return DeclResult();
4379-
4380-
auto IsSameTemplateArg = [&](const TemplateArgument &Arg1,
4381-
const TemplateArgument &Arg2) {
4382-
return Context.isSameTemplateArgument(Arg1, Arg2);
4383-
};
4384-
4385-
if (VarDecl *Var = Template->getTemplatedDecl();
4386-
ParsingInitForAutoVars.count(Var) &&
4387-
llvm::equal(
4388-
CTAI.CanonicalConverted,
4389-
Template->getTemplateParameters()->getInjectedTemplateArgs(Context),
4390-
IsSameTemplateArg)) {
4391-
Diag(TemplateNameLoc,
4392-
diag::err_auto_variable_cannot_appear_in_own_initializer)
4393-
<< diag::ParsingInitFor::VarTemplate << Var << Var->getType();
4394-
return true;
4395-
}
4396-
4397-
SmallVector<VarTemplatePartialSpecializationDecl *, 4> PartialSpecs;
4398-
Template->getPartialSpecializations(PartialSpecs);
4399-
for (VarTemplatePartialSpecializationDecl *Partial : PartialSpecs)
4400-
if (ParsingInitForAutoVars.count(Partial) &&
4401-
llvm::equal(CTAI.CanonicalConverted,
4402-
Partial->getTemplateArgs().asArray(),
4403-
IsSameTemplateArg)) {
4404-
Diag(TemplateNameLoc,
4405-
diag::err_auto_variable_cannot_appear_in_own_initializer)
4406-
<< diag::ParsingInitFor::VarTemplatePartialSpec << Partial
4407-
<< Partial->getType();
4408-
return true;
4409-
}
4410-
4376+
TemplateArgs, CTAI.CanonicalConverted))
44114377
return DeclResult();
4412-
}
44134378

44144379
// Find the variable template specialization declaration that
44154380
// corresponds to these arguments.
44164381
void *InsertPos = nullptr;
44174382
if (VarTemplateSpecializationDecl *Spec =
44184383
Template->findSpecialization(CTAI.CanonicalConverted, InsertPos)) {
44194384
checkSpecializationReachability(TemplateNameLoc, Spec);
4420-
if (Spec->getType()->isUndeducedType()) {
4421-
if (ParsingInitForAutoVars.count(Spec))
4422-
Diag(TemplateNameLoc,
4423-
diag::err_auto_variable_cannot_appear_in_own_initializer)
4424-
<< diag::ParsingInitFor::VarTemplateExplicitSpec << Spec
4425-
<< Spec->getType();
4426-
else
4427-
// We are substituting the initializer of this variable template
4428-
// specialization.
4429-
Diag(TemplateNameLoc, diag::err_var_template_spec_type_depends_on_self)
4430-
<< Spec << Spec->getType();
4431-
4432-
return true;
4433-
}
44344385
// If we already have a variable template specialization, return it.
44354386
return Spec;
44364387
}

clang/lib/Sema/SemaTemplateDeduction.cpp

Lines changed: 80 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,27 @@ namespace clang {
114114
using namespace clang;
115115
using namespace sema;
116116

117+
/// Compare two APSInts, extending and switching the sign as
118+
/// necessary to compare their values regardless of underlying type.
119+
static bool hasSameExtendedValue(llvm::APSInt X, llvm::APSInt Y) {
120+
if (Y.getBitWidth() > X.getBitWidth())
121+
X = X.extend(Y.getBitWidth());
122+
else if (Y.getBitWidth() < X.getBitWidth())
123+
Y = Y.extend(X.getBitWidth());
124+
125+
// If there is a signedness mismatch, correct it.
126+
if (X.isSigned() != Y.isSigned()) {
127+
// If the signed value is negative, then the values cannot be the same.
128+
if ((Y.isSigned() && Y.isNegative()) || (X.isSigned() && X.isNegative()))
129+
return false;
130+
131+
Y.setIsSigned(true);
132+
X.setIsSigned(true);
133+
}
134+
135+
return X == Y;
136+
}
137+
117138
/// The kind of PartialOrdering we're performing template argument deduction
118139
/// for (C++11 [temp.deduct.partial]).
119140
enum class PartialOrderingKind { None, NonCall, Call };
@@ -252,7 +273,7 @@ checkDeducedTemplateArguments(ASTContext &Context,
252273
if (Y.getKind() == TemplateArgument::Expression ||
253274
Y.getKind() == TemplateArgument::Declaration ||
254275
(Y.getKind() == TemplateArgument::Integral &&
255-
llvm::APSInt::isSameValue(X.getAsIntegral(), Y.getAsIntegral())))
276+
hasSameExtendedValue(X.getAsIntegral(), Y.getAsIntegral())))
256277
return X.wasDeducedFromArrayBound() ? Y : X;
257278

258279
// All other combinations are incompatible.
@@ -2553,7 +2574,7 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams,
25532574

25542575
case TemplateArgument::Integral:
25552576
if (A.getKind() == TemplateArgument::Integral) {
2556-
if (llvm::APSInt::isSameValue(P.getAsIntegral(), A.getAsIntegral()))
2577+
if (hasSameExtendedValue(P.getAsIntegral(), A.getAsIntegral()))
25572578
return TemplateDeductionResult::Success;
25582579
}
25592580
Info.FirstArg = P;
@@ -2807,6 +2828,62 @@ TemplateDeductionResult Sema::DeduceTemplateArguments(
28072828
/*HasDeducedAnyParam=*/nullptr);
28082829
}
28092830

2831+
/// Determine whether two template arguments are the same.
2832+
static bool isSameTemplateArg(ASTContext &Context, const TemplateArgument &X,
2833+
const TemplateArgument &Y) {
2834+
if (X.getKind() != Y.getKind())
2835+
return false;
2836+
2837+
switch (X.getKind()) {
2838+
case TemplateArgument::Null:
2839+
llvm_unreachable("Comparing NULL template argument");
2840+
2841+
case TemplateArgument::Type:
2842+
return Context.getCanonicalType(X.getAsType()) ==
2843+
Context.getCanonicalType(Y.getAsType());
2844+
2845+
case TemplateArgument::Declaration:
2846+
return isSameDeclaration(X.getAsDecl(), Y.getAsDecl());
2847+
2848+
case TemplateArgument::NullPtr:
2849+
return Context.hasSameType(X.getNullPtrType(), Y.getNullPtrType());
2850+
2851+
case TemplateArgument::Template:
2852+
case TemplateArgument::TemplateExpansion:
2853+
return Context.getCanonicalTemplateName(
2854+
X.getAsTemplateOrTemplatePattern()).getAsVoidPointer() ==
2855+
Context.getCanonicalTemplateName(
2856+
Y.getAsTemplateOrTemplatePattern()).getAsVoidPointer();
2857+
2858+
case TemplateArgument::Integral:
2859+
return hasSameExtendedValue(X.getAsIntegral(), Y.getAsIntegral());
2860+
2861+
case TemplateArgument::StructuralValue:
2862+
return X.structurallyEquals(Y);
2863+
2864+
case TemplateArgument::Expression: {
2865+
llvm::FoldingSetNodeID XID, YID;
2866+
X.getAsExpr()->Profile(XID, Context, true);
2867+
Y.getAsExpr()->Profile(YID, Context, true);
2868+
return XID == YID;
2869+
}
2870+
2871+
case TemplateArgument::Pack: {
2872+
unsigned PackIterationSize = X.pack_size();
2873+
if (X.pack_size() != Y.pack_size())
2874+
return false;
2875+
ArrayRef<TemplateArgument> XP = X.pack_elements();
2876+
ArrayRef<TemplateArgument> YP = Y.pack_elements();
2877+
for (unsigned i = 0; i < PackIterationSize; ++i)
2878+
if (!isSameTemplateArg(Context, XP[i], YP[i]))
2879+
return false;
2880+
return true;
2881+
}
2882+
}
2883+
2884+
llvm_unreachable("Invalid TemplateArgument Kind!");
2885+
}
2886+
28102887
TemplateArgumentLoc
28112888
Sema::getTrivialTemplateArgumentLoc(const TemplateArgument &Arg,
28122889
QualType NTTPType, SourceLocation Loc,
@@ -3272,7 +3349,7 @@ static TemplateDeductionResult FinishTemplateArgumentDeduction(
32723349
break;
32733350
TemplateArgument PP = P.isPackExpansion() ? P.getPackExpansionPattern() : P,
32743351
PA = A.isPackExpansion() ? A.getPackExpansionPattern() : A;
3275-
if (!S.Context.isSameTemplateArgument(PP, PA)) {
3352+
if (!isSameTemplateArg(S.Context, PP, PA)) {
32763353
if (!P.isPackExpansion() && !A.isPackExpansion()) {
32773354
Info.Param = makeTemplateParameter(TPL->getParam(
32783355
(AsStack.empty() ? As.end() : AsStack.back().begin()) -

clang/test/SemaCXX/cxx1y-variable-templates_in_class.cpp

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -412,26 +412,6 @@ namespace dependent_static_var_template {
412412
}
413413

414414
int cf() { return F<int>(); }
415-
416-
#ifdef CPP1Y
417-
namespace GH55872 {
418-
struct s {
419-
template<typename T>
420-
static CONST auto f = [] { return T::template g<s>; };
421-
// expected-note@-1 {{in instantiation of static data member 'dependent_static_var_template::GH55872::t::g' requested here}}
422-
// expected-note@-2 {{while substituting into a lambda expression here}}
423-
};
424-
425-
struct t {
426-
template<typename T>
427-
static CONST auto g = [] { return T::template f<t>; };
428-
// expected-error@-1 {{the type of variable template specialization 'f<dependent_static_var_template::GH55872::t>' declared with deduced type 'const auto' depends on itself}}
429-
// expected-note@-2 {{while substituting into a lambda expression here}}
430-
};
431-
432-
void test() { s::f<t>()(); } // expected-note {{in instantiation of static data member 'dependent_static_var_template::GH55872::s::f' requested here}}
433-
}
434-
#endif
435415
}
436416

437417
#ifndef PRECXX11

clang/test/SemaCXX/cxx1y-variable-templates_top_level.cpp

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -492,21 +492,4 @@ static_assert(C<int, 0,1,2,3,4>::VALUEARRAY[3] == 3, "");
492492
static_assert(C<int, 0,1,2,3,4>::VALUEARRAY[0] == 0, "");
493493

494494
}
495-
496-
namespace appear_in_its_own_init {
497-
template <class T>
498-
auto GH51347 = GH51347<T>; // expected-error {{variable template 'GH51347' declared with deduced type 'auto' cannot appear in its own initializer}}
499-
500-
template <class T, class... Ts>
501-
auto a = [] {
502-
using U = T;
503-
a<U, Ts...>; // expected-error {{variable template 'a' declared with deduced type 'auto' cannot appear in its own initializer}}
504-
};
505-
506-
template <int...> int b;
507-
template <int I>
508-
auto b<I, I * 2, 5> = b<I, I * 2, 5l>; // expected-error {{variable template partial specialization 'b<I, I * 2, 5>' declared with deduced type 'auto' cannot appear in its own initializer}}
509-
template <> auto b<0, 0, 0> = b<0, 0, 0>; // expected-error {{variable template explicit specialization 'b<0, 0, 0>' declared with deduced type 'auto' cannot appear in its own initializer}}
510-
}
511-
512495
#endif

clang/test/SemaTemplate/instantiate-var-template.cpp

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -47,14 +47,3 @@ namespace InvalidInsertPos {
4747
template<> int v<int, 0>;
4848
int k = v<int, 500>;
4949
}
50-
51-
namespace GH97881_comment {
52-
template <bool B>
53-
auto g = sizeof(g<!B>);
54-
// expected-error@-1 {{the type of variable template specialization 'g<false>'}}
55-
// expected-note@-2 {{in instantiation of variable template specialization 'GH97881_comment::g'}}
56-
57-
void test() {
58-
(void)sizeof(g<false>); // expected-note {{in instantiation of variable template specialization 'GH97881_comment::g'}}
59-
}
60-
}

0 commit comments

Comments
 (0)