Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -414,6 +414,8 @@ Bug Fixes to C++ Support
- Clang now issues an error when placement new is used to modify a const-qualified variable
in a ``constexpr`` function. (#GH131432)
- Clang now emits a warning when class template argument deduction for alias templates is used in C++17. (#GH133806)
- No longer crashes when instantiating invalid variable template specialization
whose type depends on itself. (#GH51347)

Bug Fixes to AST Handling
^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down
14 changes: 11 additions & 3 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -2495,9 +2495,14 @@ def note_implicit_deduction_guide : Note<"implicit deduction guide declared as '
def warn_cxx98_compat_auto_type_specifier : Warning<
"'auto' type specifier is incompatible with C++98">,
InGroup<CXX98Compat>, DefaultIgnore;
def err_auto_variable_cannot_appear_in_own_initializer : Error<
"variable %0 declared with deduced type %1 "
"cannot appear in its own initializer">;
def err_auto_variable_cannot_appear_in_own_initializer
: Error<
"%enum_select<ParsingInitFor>{%Var{variable}|"
"%VarTemplate{variable template}|"
"%VarTemplatePartialSpec{variable template partial specialization}|"
"%VarTemplateExplicitSpec{variable template explicit "
"specialization}}0 %1 "
"declared with deduced type %2 cannot appear in its own initializer">;
def err_binding_cannot_appear_in_own_initializer : Error<
"binding %0 cannot appear in the initializer of its own "
"decomposition declaration">;
Expand Down Expand Up @@ -5259,6 +5264,9 @@ def err_template_member_noparams : Error<
"extraneous 'template<>' in declaration of member %0">;
def err_template_tag_noparams : Error<
"extraneous 'template<>' in declaration of %0 %1">;
def err_var_template_spec_type_depends_on_self : Error<
"the type of variable template specialization %0 declared with deduced type "
"%1 depends on itself">;

def warn_unqualified_call_to_std_cast_function : Warning<
"unqualified call to '%0'">, InGroup<DiagGroup<"unqualified-std-cast-call">>;
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/Sema/SemaExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,8 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, ArrayRef<SourceLocation> Locs,
<< D->getDeclName();
} else {
Diag(Loc, diag::err_auto_variable_cannot_appear_in_own_initializer)
<< D->getDeclName() << cast<VarDecl>(D)->getType();
<< diag::ParsingInitFor::Var << D->getDeclName()
<< cast<VarDecl>(D)->getType();
}
return true;
}
Expand Down
67 changes: 66 additions & 1 deletion clang/lib/Sema/SemaTemplate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4348,6 +4348,23 @@ struct PartialSpecMatchResult {
VarTemplatePartialSpecializationDecl *Partial;
TemplateArgumentList *Args;
};

struct TemplateArgEqualityComparator {
const ASTContext &Context;

bool operator()(const TemplateArgument &Canonical,
const TemplateArgument &Unknown) const {
llvm::FoldingSetNodeID ID1, ID2;
Canonical.Profile(ID1, Context);
Context.getCanonicalTemplateArgument(Unknown).Profile(ID2, Context);
#ifndef NDEBUG
llvm::FoldingSetNodeID ID3;
Context.getCanonicalTemplateArgument(Canonical).Profile(ID3, Context);
assert(ID1 == ID3);
#endif
return ID1 == ID2;
}
};
} // end anonymous namespace

DeclResult
Expand All @@ -4368,15 +4385,63 @@ Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc,
// Produce a placeholder value if the specialization is dependent.
if (Template->getDeclContext()->isDependentContext() ||
TemplateSpecializationType::anyDependentTemplateArguments(
TemplateArgs, CTAI.CanonicalConverted))
TemplateArgs, CTAI.CanonicalConverted)) {
if (ParsingInitForAutoVars.empty())
return DeclResult();

if (VarDecl *Var = Template->getTemplatedDecl();
ParsingInitForAutoVars.count(Var) &&
llvm::equal(
CTAI.CanonicalConverted,
Template->getTemplateParameters()->getInjectedTemplateArgs(Context),
TemplateArgEqualityComparator{Context})) {
Diag(TemplateNameLoc,
diag::err_auto_variable_cannot_appear_in_own_initializer)
<< diag::ParsingInitFor::VarTemplate << Var << Var->getType()
<< SourceRange(TemplateNameLoc, TemplateArgs.getRAngleLoc());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm also wondering if it is necessary to draw underlines under the RHS of the declaration - would that be noisy if the declaration is too long?

return true;
}

SmallVector<VarTemplatePartialSpecializationDecl *, 4> PartialSpecs;
Template->getPartialSpecializations(PartialSpecs);
for (VarTemplatePartialSpecializationDecl *Partial : PartialSpecs)
if (ParsingInitForAutoVars.count(Partial) &&
llvm::equal(CTAI.CanonicalConverted,
Partial->getTemplateArgs().asArray(),
TemplateArgEqualityComparator{Context})) {
Diag(TemplateNameLoc,
diag::err_auto_variable_cannot_appear_in_own_initializer)
<< diag::ParsingInitFor::VarTemplatePartialSpec << Partial
<< Partial->getType()
<< SourceRange(TemplateNameLoc, TemplateArgs.getRAngleLoc());
return true;
}

return DeclResult();
}

// Find the variable template specialization declaration that
// corresponds to these arguments.
void *InsertPos = nullptr;
if (VarTemplateSpecializationDecl *Spec =
Template->findSpecialization(CTAI.CanonicalConverted, InsertPos)) {
checkSpecializationReachability(TemplateNameLoc, Spec);
if (Spec->getType()->isUndeducedType()) {
if (ParsingInitForAutoVars.count(Spec))
Diag(TemplateNameLoc,
diag::err_auto_variable_cannot_appear_in_own_initializer)
<< diag::ParsingInitFor::VarTemplateExplicitSpec << Spec
<< Spec->getType()
<< SourceRange(TemplateNameLoc, TemplateArgs.getRAngleLoc());
else
// We are substituting the initializer of this variable template
// specialization.
Diag(TemplateNameLoc, diag::err_var_template_spec_type_depends_on_self)
<< Spec << Spec->getType()
<< SourceRange(TemplateNameLoc, TemplateArgs.getRAngleLoc());

return true;
}
// If we already have a variable template specialization, return it.
return Spec;
}
Expand Down
17 changes: 17 additions & 0 deletions clang/test/SemaCXX/cxx1y-variable-templates_top_level.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -492,4 +492,21 @@ static_assert(C<int, 0,1,2,3,4>::VALUEARRAY[3] == 3, "");
static_assert(C<int, 0,1,2,3,4>::VALUEARRAY[0] == 0, "");

}

namespace appear_in_its_own_init {
template <class T>
auto GH51347 = GH51347<T>; // expected-error {{variable template 'GH51347' declared with deduced type 'auto' cannot appear in its own initializer}}

template <class T, class... Ts>
auto a = [] {
using U = T;
a<U, Ts...>; // expected-error {{variable template 'a' declared with deduced type 'auto' cannot appear in its own initializer}}
};

template <int...> int b;
template <int I>
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}}
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}}
}

#endif
11 changes: 11 additions & 0 deletions clang/test/SemaTemplate/instantiate-var-template.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,14 @@ namespace InvalidInsertPos {
template<> int v<int, 0>;
int k = v<int, 500>;
}

namespace GH97881_comment {
template <bool B>
auto g = sizeof(g<!B>);
// expected-error@-1 {{the type of variable template specialization 'g<false>'}}
// expected-note@-2 {{in instantiation of variable template specialization 'GH97881_comment::g'}}

void test() {
(void)sizeof(g<false>); // expected-note {{in instantiation of variable template specialization 'GH97881_comment::g'}}
}
}