Author: Richard Smith
Date: 2020-07-09T17:24:20-07:00
New Revision: a5569f089844209dbea2e3241460173d7b6b1420

URL: 
https://github.com/llvm/llvm-project/commit/a5569f089844209dbea2e3241460173d7b6b1420
DIFF: 
https://github.com/llvm/llvm-project/commit/a5569f089844209dbea2e3241460173d7b6b1420.diff

LOG: Push parameters into the local instantiation scope before instantiating
a default argument.

Default arguments can (after recent language changes) refer to
parameters of the same function. Make sure they're added to the local
instantiation scope before transforming a default argument so that we
can remap such references to them properly.

Added: 
    

Modified: 
    clang/include/clang/AST/Decl.h
    clang/lib/AST/Decl.cpp
    clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
    clang/test/SemaTemplate/default-arguments-cxx0x.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h
index 6c39f6aab1b9..28faa2c1fc78 100644
--- a/clang/include/clang/AST/Decl.h
+++ b/clang/include/clang/AST/Decl.h
@@ -2618,7 +2618,13 @@ class FunctionDecl : public DeclaratorDecl,
   /// Retrieve the function declaration from which this function could
   /// be instantiated, if it is an instantiation (rather than a non-template
   /// or a specialization, for example).
-  FunctionDecl *getTemplateInstantiationPattern() const;
+  ///
+  /// If \p ForDefinition is \c false, explicit specializations will be treated
+  /// as if they were implicit instantiations. This will then find the pattern
+  /// corresponding to non-definition portions of the declaration, such as
+  /// default arguments and the exception specification.
+  FunctionDecl *
+  getTemplateInstantiationPattern(bool ForDefinition = true) const;
 
   /// Retrieve the primary template that this function template
   /// specialization either specializes or was instantiated from.

diff  --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index 1676f319394d..5c0a98815dd7 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -3623,7 +3623,8 @@ bool FunctionDecl::isTemplateInstantiation() const {
   return clang::isTemplateInstantiation(getTemplateSpecializationKind());
 }
 
-FunctionDecl *FunctionDecl::getTemplateInstantiationPattern() const {
+FunctionDecl *
+FunctionDecl::getTemplateInstantiationPattern(bool ForDefinition) const {
   // If this is a generic lambda call operator specialization, its
   // instantiation pattern is always its primary template's pattern
   // even if its primary template was instantiated from another
@@ -3640,18 +3641,20 @@ FunctionDecl 
*FunctionDecl::getTemplateInstantiationPattern() const {
   }
 
   if (MemberSpecializationInfo *Info = getMemberSpecializationInfo()) {
-    if (!clang::isTemplateInstantiation(Info->getTemplateSpecializationKind()))
+    if (ForDefinition &&
+        !clang::isTemplateInstantiation(Info->getTemplateSpecializationKind()))
       return nullptr;
     return 
getDefinitionOrSelf(cast<FunctionDecl>(Info->getInstantiatedFrom()));
   }
 
-  if (!clang::isTemplateInstantiation(getTemplateSpecializationKind()))
+  if (ForDefinition &&
+      !clang::isTemplateInstantiation(getTemplateSpecializationKind()))
     return nullptr;
 
   if (FunctionTemplateDecl *Primary = getPrimaryTemplate()) {
     // If we hit a point where the user provided a specialization of this
     // template, we're done looking.
-    while (!Primary->isMemberSpecialization()) {
+    while (!ForDefinition || !Primary->isMemberSpecialization()) {
       auto *NewPrimary = Primary->getInstantiatedFromMemberTemplate();
       if (!NewPrimary)
         break;

diff  --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp 
b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 1098a9aa782c..6179d90d54f7 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -4273,6 +4273,13 @@ bool Sema::InstantiateDefaultArgument(SourceLocation 
CallLoc, FunctionDecl *FD,
     //   default argument expression appears.
     ContextRAII SavedContext(*this, FD);
     LocalInstantiationScope Local(*this);
+
+    FunctionDecl *Pattern = FD->getTemplateInstantiationPattern(
+        /*ForDefinition*/ false);
+    if (addInstantiatedParametersToScope(*this, FD, Pattern, Local,
+                                         TemplateArgs))
+      return true;
+
     runWithSufficientStackSpace(CallLoc, [&] {
       Result = SubstInitializer(UninstExpr, TemplateArgs,
                                 /*DirectInit*/false);
@@ -4338,6 +4345,10 @@ void Sema::InstantiateExceptionSpec(SourceLocation 
PointOfInstantiation,
   MultiLevelTemplateArgumentList TemplateArgs =
     getTemplateInstantiationArgs(Decl, nullptr, /*RelativeToPrimary*/true);
 
+  // FIXME: We can't use getTemplateInstantiationPattern(false) in general
+  // here, because for a non-defining friend declaration in a class template,
+  // we don't store enough information to map back to the friend declaration in
+  // the template.
   FunctionDecl *Template = Proto->getExceptionSpecTemplate();
   if (addInstantiatedParametersToScope(*this, Decl, Template, Scope,
                                        TemplateArgs)) {

diff  --git a/clang/test/SemaTemplate/default-arguments-cxx0x.cpp 
b/clang/test/SemaTemplate/default-arguments-cxx0x.cpp
index 2114cc94e6c6..02696a80bc0f 100644
--- a/clang/test/SemaTemplate/default-arguments-cxx0x.cpp
+++ b/clang/test/SemaTemplate/default-arguments-cxx0x.cpp
@@ -116,6 +116,11 @@ namespace rdar34167492 {
   };
 }
 
+namespace use_of_earlier_param {
+  template<typename T> void f(T a, int = decltype(a)());
+  void g() { f(0); }
+}
+
 #if __cplusplus >= 201402L
 namespace lambda {
   // Verify that a default argument in a lambda can refer to the type of a


        
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to