diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 9bfa71dc8bcf1d..a381d876a54c67 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -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(Base.dyn_cast()); // 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() || @@ -7423,8 +7423,6 @@ 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(Base.dyn_cast()); if (Base && (!VD || isa(VD))) { @@ -7432,24 +7430,30 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, << 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(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()) diff --git a/clang/test/CoverageMapping/templates.cpp b/clang/test/CoverageMapping/templates.cpp index 7010edbc32c34a..143e566a33cb85 100644 --- a/clang/test/CoverageMapping/templates.cpp +++ b/clang/test/CoverageMapping/templates.cpp @@ -19,3 +19,16 @@ int main() { func(true); return 0; } + +namespace structural_value_crash { + template + void tpl_fn() { + (void)p; + } + + int arr[] = {1, 2, 3}; + + void test() { + tpl_fn(); + } +}