r282651 - P0127R2: Support type deduction for types of non-type template parameters in

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Wed Sep 28 16:55:28 PDT 2016


Author: rsmith
Date: Wed Sep 28 18:55:27 2016
New Revision: 282651

URL: http://llvm.org/viewvc/llvm-project?rev=282651&view=rev
Log:
P0127R2: Support type deduction for types of non-type template parameters in
C++1z.

Patch by James Touton! Some bugfixes and rebasing by me.

Modified:
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/lib/Lex/PPMacroExpansion.cpp
    cfe/trunk/lib/Sema/SemaTemplate.cpp
    cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp
    cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
    cfe/trunk/lib/Sema/SemaType.cpp
    cfe/trunk/test/SemaTemplate/temp_arg_nontype_cxx11.cpp
    cfe/trunk/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=282651&r1=282650&r2=282651&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Wed Sep 28 18:55:27 2016
@@ -1827,7 +1827,8 @@ def err_auto_not_allowed : Error<
   "|in exception declaration|in template parameter|in block literal"
   "|in template argument|in typedef|in type alias|in function return type"
   "|in conversion function type|here|in lambda parameter"
-  "|in type allocated by 'new'|in K&R-style function parameter}1">;
+  "|in type allocated by 'new'|in K&R-style function parameter}1"
+  "%select{|||||||| until C++1z||||||||||}1">;
 def err_auto_not_allowed_var_inst : Error<
   "'auto' variable template instantiation is not allowed">;
 def err_auto_var_requires_init : Error<
@@ -3656,6 +3657,10 @@ def note_template_nontype_parm_prev_decl
   "previous non-type template parameter with type %0 is here">;
 def err_template_nontype_parm_bad_type : Error<
   "a non-type template parameter cannot have type %0">;
+def warn_cxx14_compat_template_nontype_parm_auto_type : Warning<
+  "non-type template parameters declared with %0 are incompatible with C++ "
+  "standards before C++1z">,
+  DefaultIgnore, InGroup<CXXPre1zCompat>;
 def err_template_param_default_arg_redefinition : Error<
   "template parameter redefines default argument">;
 def note_template_param_prev_default_arg : Note<
@@ -3750,8 +3755,10 @@ def warn_cxx98_compat_template_arg_null
 def err_template_arg_untyped_null_constant : Error<
   "null non-type template argument must be cast to template parameter type %0">;
 def err_template_arg_wrongtype_null_constant : Error<
- "null non-type template argument of type %0 does not match template parameter "
- "of type %1">;
+  "null non-type template argument of type %0 does not match template parameter "
+  "of type %1">;
+def err_non_type_template_parm_type_deduction_failure : Error<
+  "non-type template parameter %0 with type %1 has incompatible initializer of type %2">;
 def err_deduced_non_type_template_arg_type_mismatch : Error<
   "deduced non-type template argument does not have the same type as the "
   "its corresponding template parameter%diff{ ($ vs $)|}0,1">;

Modified: cfe/trunk/lib/Lex/PPMacroExpansion.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/PPMacroExpansion.cpp?rev=282651&r1=282650&r2=282651&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/PPMacroExpansion.cpp (original)
+++ cfe/trunk/lib/Lex/PPMacroExpansion.cpp Wed Sep 28 18:55:27 2016
@@ -1202,6 +1202,8 @@ static bool HasFeature(const Preprocesso
       .Case("cxx_relaxed_constexpr", LangOpts.CPlusPlus14)
       .Case("cxx_return_type_deduction", LangOpts.CPlusPlus14)
       .Case("cxx_variable_templates", LangOpts.CPlusPlus14)
+      // C++1z features
+      .Case("cxx_template_auto", LangOpts.CPlusPlus1z)
       // C++ TSes
       //.Case("cxx_runtime_arrays", LangOpts.CPlusPlusTSArrays)
       //.Case("cxx_concepts", LangOpts.CPlusPlusTSConcepts)

Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=282651&r1=282650&r2=282651&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Wed Sep 28 18:55:27 2016
@@ -730,7 +730,13 @@ Sema::CheckNonTypeTemplateParameterType(
       T->isNullPtrType() ||
       // If T is a dependent type, we can't do the check now, so we
       // assume that it is well-formed.
-      T->isDependentType()) {
+      T->isDependentType() ||
+      // Allow use of auto in template parameter declarations.
+      T->isUndeducedType()) {
+    if (T->isUndeducedType()) {
+      Diag(Loc, diag::warn_cxx14_compat_template_nontype_parm_auto_type)
+          << QualType(T->getContainedAutoType(), 0);
+    }
     // C++ [temp.param]p5: The top-level cv-qualifiers on the template-parameter
     // are ignored when determining its type.
     return T.getUnqualifiedType();
@@ -4975,6 +4981,29 @@ ExprResult Sema::CheckTemplateArgument(N
                                        CheckTemplateArgumentKind CTAK) {
   SourceLocation StartLoc = Arg->getLocStart();
 
+  // If the parameter type somehow involves auto, deduce the type now.
+  if (getLangOpts().CPlusPlus1z && ParamType->isUndeducedType()) {
+    if (DeduceAutoType(
+            Context.getTrivialTypeSourceInfo(ParamType, Param->getLocation()),
+                       Arg, ParamType) == DAR_Failed) {
+      Diag(Arg->getExprLoc(),
+           diag::err_non_type_template_parm_type_deduction_failure)
+        << Param->getDeclName() << Param->getType() << Arg->getType()
+        << Arg->getSourceRange();
+      Diag(Param->getLocation(), diag::note_template_param_here);
+      return ExprError();
+    }
+    // CheckNonTypeTemplateParameterType will produce a diagnostic if there's
+    // an error. The error message normally references the parameter
+    // declaration, but here we'll pass the argument location because that's
+    // where the parameter type is deduced.
+    ParamType = CheckNonTypeTemplateParameterType(ParamType, Arg->getExprLoc());
+    if (ParamType.isNull()) {
+      Diag(Param->getLocation(), diag::note_template_param_here);
+      return ExprError();
+    }
+  }
+
   // If either the parameter has a dependent type or the argument is
   // type-dependent, there's nothing we can check now.
   if (ParamType->isDependentType() || Arg->isTypeDependent()) {
@@ -7255,7 +7284,7 @@ Sema::CheckMemberSpecialization(NamedDec
       if (InstantiationFunction->isDeleted()) {
         assert(InstantiationFunction->getCanonicalDecl() ==
                InstantiationFunction);
-        InstantiationFunction->setDeletedAsWritten(false);
+        InstantiationFunction->setDeletedAsWritten(false);
       }
     }
 

Modified: cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp?rev=282651&r1=282650&r2=282651&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp Wed Sep 28 18:55:27 2016
@@ -100,7 +100,8 @@ DeduceTemplateArgumentsByTypeMatch(Sema
                                    SmallVectorImpl<DeducedTemplateArgument> &
                                                       Deduced,
                                    unsigned TDF,
-                                   bool PartialOrdering = false);
+                                   bool PartialOrdering = false,
+                                   bool DeducedFromArrayBound = false);
 
 static Sema::TemplateDeductionResult
 DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams,
@@ -167,6 +168,12 @@ checkDeducedTemplateArguments(ASTContext
         Context.hasSameType(X.getAsType(), Y.getAsType()))
       return X;
 
+    // If one of the two arguments was deduced from an array bound, the other
+    // supersedes it.
+    if (X.wasDeducedFromArrayBound() != Y.wasDeducedFromArrayBound())
+      return X.wasDeducedFromArrayBound() ? Y : X;
+
+    // The arguments are not compatible.
     return DeducedTemplateArgument();
 
   case TemplateArgument::Integral:
@@ -287,7 +294,8 @@ checkDeducedTemplateArguments(ASTContext
 /// \brief Deduce the value of the given non-type template parameter
 /// from the given integral constant.
 static Sema::TemplateDeductionResult DeduceNonTypeTemplateArgument(
-    Sema &S, NonTypeTemplateParmDecl *NTTP, const llvm::APSInt &Value,
+    Sema &S, TemplateParameterList *TemplateParams,
+    NonTypeTemplateParmDecl *NTTP, const llvm::APSInt &Value,
     QualType ValueType, bool DeducedFromArrayBound, TemplateDeductionInfo &Info,
     SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
   assert(NTTP->getDepth() == 0 &&
@@ -306,13 +314,20 @@ static Sema::TemplateDeductionResult Ded
   }
 
   Deduced[NTTP->getIndex()] = Result;
-  return Sema::TDK_Success;
+  return S.getLangOpts().CPlusPlus1z
+             ? DeduceTemplateArgumentsByTypeMatch(
+                   S, TemplateParams, NTTP->getType(), ValueType, Info, Deduced,
+                   TDF_ParamWithReferenceType | TDF_SkipNonDependent,
+                   /*PartialOrdering=*/false,
+                   /*ArrayBound=*/DeducedFromArrayBound)
+             : Sema::TDK_Success;
 }
 
 /// \brief Deduce the value of the given non-type template parameter
 /// from the given null pointer template argument type.
 static Sema::TemplateDeductionResult DeduceNullPtrTemplateArgument(
-    Sema &S, NonTypeTemplateParmDecl *NTTP, QualType NullPtrType,
+    Sema &S, TemplateParameterList *TemplateParams,
+    NonTypeTemplateParmDecl *NTTP, QualType NullPtrType,
     TemplateDeductionInfo &Info,
     SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
   Expr *Value =
@@ -332,7 +347,11 @@ static Sema::TemplateDeductionResult Ded
   }
 
   Deduced[NTTP->getIndex()] = Result;
-  return Sema::TDK_Success;
+  return S.getLangOpts().CPlusPlus1z
+             ? DeduceTemplateArgumentsByTypeMatch(
+                   S, TemplateParams, NTTP->getType(), Value->getType(), Info,
+                   Deduced, TDF_ParamWithReferenceType | TDF_SkipNonDependent)
+             : Sema::TDK_Success;
 }
 
 /// \brief Deduce the value of the given non-type template parameter
@@ -341,6 +360,7 @@ static Sema::TemplateDeductionResult Ded
 /// \returns true if deduction succeeded, false otherwise.
 static Sema::TemplateDeductionResult
 DeduceNonTypeTemplateArgument(Sema &S,
+                              TemplateParameterList *TemplateParams,
                               NonTypeTemplateParmDecl *NTTP,
                               Expr *Value,
                               TemplateDeductionInfo &Info,
@@ -363,7 +383,11 @@ DeduceNonTypeTemplateArgument(Sema &S,
   }
 
   Deduced[NTTP->getIndex()] = Result;
-  return Sema::TDK_Success;
+  return S.getLangOpts().CPlusPlus1z
+             ? DeduceTemplateArgumentsByTypeMatch(
+                   S, TemplateParams, NTTP->getType(), Value->getType(), Info,
+                   Deduced, TDF_ParamWithReferenceType | TDF_SkipNonDependent)
+             : Sema::TDK_Success;
 }
 
 /// \brief Deduce the value of the given non-type template parameter
@@ -372,8 +396,9 @@ DeduceNonTypeTemplateArgument(Sema &S,
 /// \returns true if deduction succeeded, false otherwise.
 static Sema::TemplateDeductionResult
 DeduceNonTypeTemplateArgument(Sema &S,
+                            TemplateParameterList *TemplateParams,
                             NonTypeTemplateParmDecl *NTTP,
-                            ValueDecl *D,
+                            ValueDecl *D, QualType T,
                             TemplateDeductionInfo &Info,
                             SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
   assert(NTTP->getDepth() == 0 &&
@@ -393,7 +418,11 @@ DeduceNonTypeTemplateArgument(Sema &S,
   }
 
   Deduced[NTTP->getIndex()] = Result;
-  return Sema::TDK_Success;
+  return S.getLangOpts().CPlusPlus1z
+             ? DeduceTemplateArgumentsByTypeMatch(
+                   S, TemplateParams, NTTP->getType(), T, Info, Deduced,
+                   TDF_ParamWithReferenceType | TDF_SkipNonDependent)
+             : Sema::TDK_Success;
 }
 
 static Sema::TemplateDeductionResult
@@ -968,7 +997,8 @@ DeduceTemplateArgumentsByTypeMatch(Sema
                                    TemplateDeductionInfo &Info,
                             SmallVectorImpl<DeducedTemplateArgument> &Deduced,
                                    unsigned TDF,
-                                   bool PartialOrdering) {
+                                   bool PartialOrdering,
+                                   bool DeducedFromArrayBound) {
   // We only want to look at the canonical types, since typedefs and
   // sugar are not part of template argument deduction.
   QualType Param = S.Context.getCanonicalType(ParamIn);
@@ -1152,7 +1182,7 @@ DeduceTemplateArgumentsByTypeMatch(Sema
     if (RecanonicalizeArg)
       DeducedType = S.Context.getCanonicalType(DeducedType);
 
-    DeducedTemplateArgument NewDeduced(DeducedType);
+    DeducedTemplateArgument NewDeduced(DeducedType, DeducedFromArrayBound);
     DeducedTemplateArgument Result = checkDeducedTemplateArguments(S.Context,
                                                                  Deduced[Index],
                                                                    NewDeduced);
@@ -1374,7 +1404,7 @@ DeduceTemplateArgumentsByTypeMatch(Sema
       if (const ConstantArrayType *ConstantArrayArg
             = dyn_cast<ConstantArrayType>(ArrayArg)) {
         llvm::APSInt Size(ConstantArrayArg->getSize());
-        return DeduceNonTypeTemplateArgument(S, NTTP, Size,
+        return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP, Size,
                                              S.Context.getSizeType(),
                                              /*ArrayBound=*/true,
                                              Info, Deduced);
@@ -1382,7 +1412,7 @@ DeduceTemplateArgumentsByTypeMatch(Sema
       if (const DependentSizedArrayType *DependentArrayArg
             = dyn_cast<DependentSizedArrayType>(ArrayArg))
         if (DependentArrayArg->getSizeExpr())
-          return DeduceNonTypeTemplateArgument(S, NTTP,
+          return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP,
                                                DependentArrayArg->getSizeExpr(),
                                                Info, Deduced);
 
@@ -1654,8 +1684,8 @@ DeduceTemplateArgumentsByTypeMatch(Sema
 
         llvm::APSInt ArgSize(S.Context.getTypeSize(S.Context.IntTy), false);
         ArgSize = VectorArg->getNumElements();
-        return DeduceNonTypeTemplateArgument(S, NTTP, ArgSize, S.Context.IntTy,
-                                             false, Info, Deduced);
+        return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP, ArgSize,
+                                             S.Context.IntTy, false, Info, Deduced);
       }
 
       if (const DependentSizedExtVectorType *VectorArg
@@ -1674,7 +1704,8 @@ DeduceTemplateArgumentsByTypeMatch(Sema
         if (!NTTP)
           return Sema::TDK_Success;
 
-        return DeduceNonTypeTemplateArgument(S, NTTP, VectorArg->getSizeExpr(),
+        return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP,
+                                             VectorArg->getSizeExpr(),
                                              Info, Deduced);
       }
 
@@ -1779,19 +1810,22 @@ DeduceTemplateArguments(Sema &S,
     if (NonTypeTemplateParmDecl *NTTP
           = getDeducedParameterFromExpr(Param.getAsExpr())) {
       if (Arg.getKind() == TemplateArgument::Integral)
-        return DeduceNonTypeTemplateArgument(S, NTTP,
+        return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP,
                                              Arg.getAsIntegral(),
                                              Arg.getIntegralType(),
                                              /*ArrayBound=*/false,
                                              Info, Deduced);
       if (Arg.getKind() == TemplateArgument::NullPtr)
-        return DeduceNullPtrTemplateArgument(S, NTTP, Arg.getNullPtrType(),
+        return DeduceNullPtrTemplateArgument(S, TemplateParams, NTTP,
+                                             Arg.getNullPtrType(),
                                              Info, Deduced);
       if (Arg.getKind() == TemplateArgument::Expression)
-        return DeduceNonTypeTemplateArgument(S, NTTP, Arg.getAsExpr(),
-                                             Info, Deduced);
+        return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP,
+                                             Arg.getAsExpr(), Info, Deduced);
       if (Arg.getKind() == TemplateArgument::Declaration)
-        return DeduceNonTypeTemplateArgument(S, NTTP, Arg.getAsDecl(),
+        return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP,
+                                             Arg.getAsDecl(),
+                                             Arg.getParamTypeForDecl(),
                                              Info, Deduced);
 
       Info.FirstArg = Param;
@@ -3280,7 +3314,7 @@ DeduceFromInitializerList(Sema &S, Templ
                        ILE->getNumInits());
 
       Result = DeduceNonTypeTemplateArgument(
-          S, NTTP, llvm::APSInt(Size), NTTP->getType(),
+          S, TemplateParams, NTTP, llvm::APSInt(Size), NTTP->getType(),
           /*ArrayBound=*/true, Info, Deduced);
     }
   }
@@ -4700,6 +4734,11 @@ MarkUsedTemplateParameters(ASTContext &C
 
   if (NTTP->getDepth() == Depth)
     Used[NTTP->getIndex()] = true;
+
+  // In C++1z mode, additional arguments may be deduced from the type of a
+  // non-type argument.
+  if (Ctx.getLangOpts().CPlusPlus1z)
+    MarkUsedTemplateParameters(Ctx, NTTP->getType(), OnlyDeduced, Depth, Used);
 }
 
 /// \brief Mark the template parameters that are used by the given
@@ -4946,7 +4985,7 @@ MarkUsedTemplateParameters(ASTContext &C
   case Type::UnaryTransform:
     if (!OnlyDeduced)
       MarkUsedTemplateParameters(Ctx,
-                               cast<UnaryTransformType>(T)->getUnderlyingType(),
+                                 cast<UnaryTransformType>(T)->getUnderlyingType(),
                                  OnlyDeduced, Depth, Used);
     break;
 

Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp?rev=282651&r1=282650&r2=282651&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp Wed Sep 28 18:55:27 2016
@@ -1179,8 +1179,8 @@ ExprResult TemplateInstantiator::transfo
                         cast<PackExpansionType>(parm->getType())->getPattern(),
                                      TemplateArgs, loc, parm->getDeclName());
     } else {
-      type = SemaRef.SubstType(parm->getType(), TemplateArgs, 
-                               loc, parm->getDeclName());
+      type = SemaRef.SubstType(VD ? arg.getParamTypeForDecl() : arg.getNullPtrType(),
+                               TemplateArgs, loc, parm->getDeclName());
     }
     assert(!type.isNull() && "type substitution failed for param type");
     assert(!type->isDependentType() && "param type still dependent");

Modified: cfe/trunk/lib/Sema/SemaType.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=282651&r1=282650&r2=282651&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaType.cpp (original)
+++ cfe/trunk/lib/Sema/SemaType.cpp Wed Sep 28 18:55:27 2016
@@ -1582,7 +1582,14 @@ static QualType ConvertDeclSpecToType(Ty
       // template type parameter.
       Result = QualType(CorrespondingTemplateParam->getTypeForDecl(), 0);
     } else {
-      Result = Context.getAutoType(QualType(), AutoTypeKeyword::Auto, false);
+      // If auto appears in the declaration of a template parameter, treat
+      // the parameter as type-dependent.
+      bool IsDependent =
+        S.getLangOpts().CPlusPlus1z &&
+        declarator.getContext() == Declarator::TemplateParamContext;
+      Result = Context.getAutoType(QualType(),
+                                   AutoTypeKeyword::Auto,
+                                   IsDependent);
     }
     break;
 
@@ -2858,7 +2865,8 @@ static QualType GetDeclSpecTypeForDeclar
       Error = 7; // Exception declaration
       break;
     case Declarator::TemplateParamContext:
-      Error = 8; // Template parameter
+      if (!SemaRef.getLangOpts().CPlusPlus1z)
+        Error = 8; // Template parameter
       break;
     case Declarator::BlockLiteralContext:
       Error = 9; // Block literal
@@ -5540,7 +5548,7 @@ static bool handleObjCOwnershipTypeAttr(
         if (Class->isArcWeakrefUnavailable()) {
           S.Diag(AttrLoc, diag::err_arc_unsupported_weak_class);
           S.Diag(ObjT->getInterfaceDecl()->getLocation(),
-                  diag::note_class_declared);
+                 diag::note_class_declared);
         }
       }
     }

Modified: cfe/trunk/test/SemaTemplate/temp_arg_nontype_cxx11.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/temp_arg_nontype_cxx11.cpp?rev=282651&r1=282650&r2=282651&view=diff
==============================================================================
--- cfe/trunk/test/SemaTemplate/temp_arg_nontype_cxx11.cpp (original)
+++ cfe/trunk/test/SemaTemplate/temp_arg_nontype_cxx11.cpp Wed Sep 28 18:55:27 2016
@@ -23,3 +23,7 @@ namespace CanonicalNullptr {
   B<int> b = MakeB<int>();
   C<int> c = MakeC<int>();
 }
+
+namespace Auto {
+  template<auto> struct A { };  // expected-error {{until C++1z}}
+}

Modified: cfe/trunk/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp?rev=282651&r1=282650&r2=282651&view=diff
==============================================================================
--- cfe/trunk/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp (original)
+++ cfe/trunk/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp Wed Sep 28 18:55:27 2016
@@ -155,3 +155,113 @@ namespace PR24921 {
   template<int> void f(int);
   template<> void f<e>() {}
 }
+
+namespace Auto {
+  namespace Basic {
+    // simple auto
+    template<auto x> constexpr auto constant = x; // expected-note {{declared here}}
+
+    auto v1 = constant<5>;
+    auto v2 = constant<true>;
+    auto v3 = constant<'a'>;
+    auto v4 = constant<2.5>;  // expected-error {{cannot have type 'double'}}
+
+    using T1 = decltype(v1);
+    using T1 = int;
+    using T2 = decltype(v2);
+    using T2 = bool;
+    using T3 = decltype(v3);
+    using T3 = char;
+
+    // pointers
+    template<auto v>    class B { };
+    template<auto* p>   class B<p> { };
+    template<auto** pp> class B<pp> { };
+    template<auto* p0>   int &f(B<p0> b);
+    template<auto** pp0> float &f(B<pp0> b);
+
+    int a, *b = &a;
+    int &r = f(B<&a>());
+    float &s = f(B<&b>());
+  }
+
+  namespace Chained {
+    // chained template argument deduction
+    template<long n> struct C { };
+    template<class T> struct D;
+    template<class T, T n> struct D<C<n>>
+    {
+        using Q = T;
+    };
+    using DQ = long;
+    using DQ = D<C<short(2)>>::Q;
+
+    // chained template argument deduction from an array bound
+    template<typename T> struct E;
+    template<typename T, T n> struct E<int[n]> {
+        using Q = T;
+    };
+    using EQ = E<int[short(42)]>::Q;
+    using EQ = decltype(sizeof 0);
+
+    template<int N> struct F;
+    template<typename T, T N> int foo(F<N> *) = delete;  // expected-note {{explicitly deleted}}
+    void foo(void *); // expected-note {{candidate function}}
+    void bar(F<0> *p) {
+        foo(p); // expected-error {{deleted function}}
+    }
+  }
+
+  namespace ArrayToPointer {
+    constexpr char s[] = "test";
+    template<const auto* p> struct S { };
+    S<s> p;
+  }
+
+  namespace DecltypeAuto {
+    template<auto v> struct A { };
+    template<decltype(auto) v> struct DA { };
+    template<auto&> struct R { };
+
+    auto n = 0; // expected-note + {{declared here}}
+    A<n> a; // expected-error {{not a constant}} expected-note {{non-const variable 'n'}}
+    DA<n> da1;  // expected-error {{not a constant}} expected-note {{non-const variable 'n'}}
+    DA<(n)> da2;
+    R<n> r;
+  }
+
+  namespace Decomposition {
+    double foo(int, bool);
+    template<auto& f> struct fn_result_type;
+
+    template<class R, class... Args, R (& f)(Args...)>
+    struct fn_result_type<f>
+    {
+        using type = R;
+    };
+
+    using R1 = fn_result_type<foo>::type;
+    using R1 = double;
+  }
+
+  namespace Variadic {
+    template<auto... vs> struct value_list { };
+
+    using size_t = decltype(sizeof 0);
+    template<size_t n, class List> struct nth_element;
+    template<size_t n, class List> constexpr auto nth_element_v = nth_element<n, List>::value;
+
+    template<size_t n, auto v0, auto... vs>
+    struct nth_element<n, value_list<v0, vs...>>
+    {
+        static constexpr auto value = nth_element<n - 1, value_list<vs...>>::value;
+    };
+    template<auto v0, auto... vs>
+    struct nth_element<0, value_list<v0, vs...>>
+    {
+        static constexpr auto value = v0;
+    };
+
+    static_assert(nth_element_v<2, value_list<'a', 27U, false>> == false, "value mismatch");
+  }
+}




More information about the cfe-commits mailing list