Skip to content

Commit

Permalink
[clang] Represent array refs as TemplateArgument::Declaration (llvm…
Browse files Browse the repository at this point in the history
…#80050)

This returns (probably temporarily) array-referring NTTP behavior to
which was prior to llvm#78041 because ~~I'm fed up~~ have no time to fix
regressions.

(cherry picked from commit 9bf4e54)
  • Loading branch information
bolshakov-a authored and tstellar committed Feb 14, 2024
1 parent 33aec02 commit b7c8dd2
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 20 deletions.
44 changes: 24 additions & 20 deletions clang/lib/Sema/SemaTemplate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7412,9 +7412,9 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
if (ArgResult.isInvalid())
return ExprError();

// Prior to C++20, enforce restrictions on possible template argument
// values.
if (!getLangOpts().CPlusPlus20 && Value.isLValue()) {
if (Value.isLValue()) {
APValue::LValueBase Base = Value.getLValueBase();
auto *VD = const_cast<ValueDecl *>(Base.dyn_cast<const ValueDecl *>());
// For a non-type template-parameter of pointer or reference type,
// the value of the constant expression shall not refer to
assert(ParamType->isPointerType() || ParamType->isReferenceType() ||
Expand All @@ -7423,33 +7423,37 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
// -- a string literal
// -- the result of a typeid expression, or
// -- a predefined __func__ variable
APValue::LValueBase Base = Value.getLValueBase();
auto *VD = const_cast<ValueDecl *>(Base.dyn_cast<const ValueDecl *>());
if (Base &&
(!VD ||
isa<LifetimeExtendedTemporaryDecl, UnnamedGlobalConstantDecl>(VD))) {
Diag(Arg->getBeginLoc(), diag::err_template_arg_not_decl_ref)
<< Arg->getSourceRange();
return ExprError();
}
// -- a subobject [until C++20]
if (Value.hasLValuePath() && Value.getLValuePath().size() == 1 &&
VD && VD->getType()->isArrayType() &&

if (Value.hasLValuePath() && Value.getLValuePath().size() == 1 && VD &&
VD->getType()->isArrayType() &&
Value.getLValuePath()[0].getAsArrayIndex() == 0 &&
!Value.isLValueOnePastTheEnd() && ParamType->isPointerType()) {
// Per defect report (no number yet):
// ... other than a pointer to the first element of a complete array
// object.
} else if (!Value.hasLValuePath() || Value.getLValuePath().size() ||
Value.isLValueOnePastTheEnd()) {
Diag(StartLoc, diag::err_non_type_template_arg_subobject)
<< Value.getAsString(Context, ParamType);
return ExprError();
SugaredConverted = TemplateArgument(VD, ParamType);
CanonicalConverted = TemplateArgument(
cast<ValueDecl>(VD->getCanonicalDecl()), CanonParamType);
return ArgResult.get();
}

// -- a subobject [until C++20]
if (!getLangOpts().CPlusPlus20) {
if (!Value.hasLValuePath() || Value.getLValuePath().size() ||
Value.isLValueOnePastTheEnd()) {
Diag(StartLoc, diag::err_non_type_template_arg_subobject)
<< Value.getAsString(Context, ParamType);
return ExprError();
}
assert((VD || !ParamType->isReferenceType()) &&
"null reference should not be a constant expression");
assert((!VD || !ParamType->isNullPtrType()) &&
"non-null value of type nullptr_t?");
}
assert((VD || !ParamType->isReferenceType()) &&
"null reference should not be a constant expression");
assert((!VD || !ParamType->isNullPtrType()) &&
"non-null value of type nullptr_t?");
}

if (Value.isAddrLabelDiff())
Expand Down
13 changes: 13 additions & 0 deletions clang/test/CoverageMapping/templates.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,16 @@ int main() {
func<bool>(true);
return 0;
}

namespace structural_value_crash {
template <int* p>
void tpl_fn() {
(void)p;
}

int arr[] = {1, 2, 3};

void test() {
tpl_fn<arr>();
}
}

0 comments on commit b7c8dd2

Please sign in to comment.