[cfe-commits] r86578 - in /cfe/trunk: lib/Sema/Sema.h lib/Sema/SemaTemplate.cpp lib/Sema/SemaTemplateInstantiate.cpp lib/Sema/SemaTemplateInstantiateDecl.cpp test/SemaTemplate/default-arguments.cpp

Douglas Gregor dgregor at apple.com
Mon Nov 9 11:17:50 PST 2009


Author: dgregor
Date: Mon Nov  9 13:17:50 2009
New Revision: 86578

URL: http://llvm.org/viewvc/llvm-project?rev=86578&view=rev
Log:
Improve instantiation of default template arguments for nested
templates. The instantiation of these default arguments must be (and
now, is) delayed until the template argument is actually used, at
which point we substitute all levels of template arguments
concurrently.

Modified:
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaTemplate.cpp
    cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
    cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
    cfe/trunk/test/SemaTemplate/default-arguments.cpp

Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=86578&r1=86577&r2=86578&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Mon Nov  9 13:17:50 2009
@@ -2844,7 +2844,8 @@
   // C++ Template Instantiation
   //
 
-  MultiLevelTemplateArgumentList getTemplateInstantiationArgs(NamedDecl *D);
+  MultiLevelTemplateArgumentList getTemplateInstantiationArgs(NamedDecl *D,
+                                     const TemplateArgumentList *Innermost = 0);
 
   /// \brief A template instantiation that is currently in progress.
   struct ActiveTemplateInstantiation {

Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=86578&r1=86577&r2=86578&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Mon Nov  9 13:17:50 2009
@@ -1449,6 +1449,102 @@
   return false;
 }
 
+/// \brief Substitute template arguments into the default template argument for
+/// the given template type parameter.
+///
+/// \param SemaRef the semantic analysis object for which we are performing
+/// the substitution.
+///
+/// \param Template the template that we are synthesizing template arguments 
+/// for.
+///
+/// \param TemplateLoc the location of the template name that started the
+/// template-id we are checking.
+///
+/// \param RAngleLoc the location of the right angle bracket ('>') that
+/// terminates the template-id.
+///
+/// \param Param the template template parameter whose default we are
+/// substituting into.
+///
+/// \param Converted the list of template arguments provided for template
+/// parameters that precede \p Param in the template parameter list.
+///
+/// \returns the substituted template argument, or NULL if an error occurred.
+static DeclaratorInfo *
+SubstDefaultTemplateArgument(Sema &SemaRef,
+                             TemplateDecl *Template,
+                             SourceLocation TemplateLoc,
+                             SourceLocation RAngleLoc,
+                             TemplateTypeParmDecl *Param,
+                             TemplateArgumentListBuilder &Converted) {
+  DeclaratorInfo *ArgType = Param->getDefaultArgumentInfo();
+
+  // If the argument type is dependent, instantiate it now based
+  // on the previously-computed template arguments.
+  if (ArgType->getType()->isDependentType()) {
+    TemplateArgumentList TemplateArgs(SemaRef.Context, Converted,
+                                      /*TakeArgs=*/false);
+    
+    MultiLevelTemplateArgumentList AllTemplateArgs
+      = SemaRef.getTemplateInstantiationArgs(Template, &TemplateArgs);
+
+    Sema::InstantiatingTemplate Inst(SemaRef, TemplateLoc,
+                                     Template, Converted.getFlatArguments(),
+                                     Converted.flatSize(),
+                                     SourceRange(TemplateLoc, RAngleLoc));
+    
+    ArgType = SemaRef.SubstType(ArgType, AllTemplateArgs,
+                                Param->getDefaultArgumentLoc(),
+                                Param->getDeclName());
+  }
+
+  return ArgType;
+}
+
+/// \brief Substitute template arguments into the default template argument for
+/// the given non-type template parameter.
+///
+/// \param SemaRef the semantic analysis object for which we are performing
+/// the substitution.
+///
+/// \param Template the template that we are synthesizing template arguments 
+/// for.
+///
+/// \param TemplateLoc the location of the template name that started the
+/// template-id we are checking.
+///
+/// \param RAngleLoc the location of the right angle bracket ('>') that
+/// terminates the template-id.
+///
+/// \param Param the template template parameter whose default we are
+/// substituting into.
+///
+/// \param Converted the list of template arguments provided for template
+/// parameters that precede \p Param in the template parameter list.
+///
+/// \returns the substituted template argument, or NULL if an error occurred.
+static Sema::OwningExprResult
+SubstDefaultTemplateArgument(Sema &SemaRef,
+                             TemplateDecl *Template,
+                             SourceLocation TemplateLoc,
+                             SourceLocation RAngleLoc,
+                             NonTypeTemplateParmDecl *Param,
+                             TemplateArgumentListBuilder &Converted) {
+  TemplateArgumentList TemplateArgs(SemaRef.Context, Converted,
+                                    /*TakeArgs=*/false);
+    
+  MultiLevelTemplateArgumentList AllTemplateArgs
+    = SemaRef.getTemplateInstantiationArgs(Template, &TemplateArgs);
+    
+  Sema::InstantiatingTemplate Inst(SemaRef, TemplateLoc,
+                                   Template, Converted.getFlatArguments(),
+                                   Converted.flatSize(),
+                                   SourceRange(TemplateLoc, RAngleLoc));
+
+  return SemaRef.SubstExpr(Param->getDefaultArgument(), AllTemplateArgs);
+}
+
 /// \brief Check that the given template argument list is well-formed
 /// for specializing the given template.
 bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
@@ -1516,44 +1612,27 @@
         if (!TTP->hasDefaultArgument())
           break;
 
-        DeclaratorInfo *ArgType = TTP->getDefaultArgumentInfo();
-
-        // If the argument type is dependent, instantiate it now based
-        // on the previously-computed template arguments.
-        if (ArgType->getType()->isDependentType()) {
-          InstantiatingTemplate Inst(*this, TemplateLoc,
-                                     Template, Converted.getFlatArguments(),
-                                     Converted.flatSize(),
-                                     SourceRange(TemplateLoc, RAngleLoc));
-
-          TemplateArgumentList TemplateArgs(Context, Converted,
-                                            /*TakeArgs=*/false);
-          ArgType = SubstType(ArgType,
-                              MultiLevelTemplateArgumentList(TemplateArgs),
-                              TTP->getDefaultArgumentLoc(),
-                              TTP->getDeclName());
-        }
-
+        DeclaratorInfo *ArgType = SubstDefaultTemplateArgument(*this, 
+                                                               Template,
+                                                               TemplateLoc,
+                                                               RAngleLoc,
+                                                               TTP,
+                                                               Converted);
         if (!ArgType)
           return true;
-
-        Arg = TemplateArgumentLoc(TemplateArgument(ArgType->getType()), ArgType);
+                                                               
+        Arg = TemplateArgumentLoc(TemplateArgument(ArgType->getType()),
+                                  ArgType);
       } else if (NonTypeTemplateParmDecl *NTTP
                    = dyn_cast<NonTypeTemplateParmDecl>(*Param)) {
         if (!NTTP->hasDefaultArgument())
           break;
 
-        InstantiatingTemplate Inst(*this, TemplateLoc,
-                                   Template, Converted.getFlatArguments(),
-                                   Converted.flatSize(),
-                                   SourceRange(TemplateLoc, RAngleLoc));
-
-        TemplateArgumentList TemplateArgs(Context, Converted,
-                                          /*TakeArgs=*/false);
-
-        Sema::OwningExprResult E
-          = SubstExpr(NTTP->getDefaultArgument(),
-                      MultiLevelTemplateArgumentList(TemplateArgs));
+        Sema::OwningExprResult E = SubstDefaultTemplateArgument(*this, Template,
+                                                                TemplateLoc, 
+                                                                RAngleLoc, 
+                                                                NTTP, 
+                                                                Converted);
         if (E.isInvalid())
           return true;
 

Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp?rev=86578&r1=86577&r2=86578&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp Mon Nov  9 13:17:50 2009
@@ -28,11 +28,20 @@
 
 /// \brief Retrieve the template argument list(s) that should be used to
 /// instantiate the definition of the given declaration.
+///
+/// \param D the declaration for which we are computing template instantiation
+/// arguments.
+///
+/// \param Innermost if non-NULL, the innermost template argument list.
 MultiLevelTemplateArgumentList
-Sema::getTemplateInstantiationArgs(NamedDecl *D) {
+Sema::getTemplateInstantiationArgs(NamedDecl *D, 
+                                   const TemplateArgumentList *Innermost) {
   // Accumulate the set of template argument lists in this structure.
   MultiLevelTemplateArgumentList Result;
 
+  if (Innermost)
+    Result.addOuterTemplateArguments(Innermost);
+  
   DeclContext *Ctx = dyn_cast<DeclContext>(D);
   if (!Ctx)
     Ctx = D->getDeclContext();

Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=86578&r1=86577&r2=86578&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Mon Nov  9 13:17:50 2009
@@ -923,18 +923,8 @@
                                  D->wasDeclaredWithTypename(),
                                  D->isParameterPack());
 
-  // FIXME: Do we actually want to perform substitution here? I don't think
-  // we do.
-  if (D->hasDefaultArgument()) {
-    DeclaratorInfo *DefaultPattern = D->getDefaultArgumentInfo();
-    DeclaratorInfo *DefaultInst
-      = SemaRef.SubstType(DefaultPattern, TemplateArgs,
-                          D->getDefaultArgumentLoc(),
-                          D->getDeclName());
-
-    Inst->setDefaultArgument(DefaultInst,
-                             D->defaultArgumentWasInherited() /* preserve? */);
-  }
+  if (D->hasDefaultArgument())
+    Inst->setDefaultArgument(D->getDefaultArgumentInfo(), false);  
 
   // Introduce this template parameter's instantiation into the instantiation 
   // scope.

Modified: cfe/trunk/test/SemaTemplate/default-arguments.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/default-arguments.cpp?rev=86578&r1=86577&r2=86578&view=diff

==============================================================================
--- cfe/trunk/test/SemaTemplate/default-arguments.cpp (original)
+++ cfe/trunk/test/SemaTemplate/default-arguments.cpp Mon Nov  9 13:17:50 2009
@@ -42,3 +42,54 @@
 struct B<void> {
   typedef B<void*> type;
 };
+
+// Nested default arguments for template parameters.
+template<typename T> struct X1 { };
+
+template<typename T>
+struct X2 {
+  template<typename U = typename X1<T>::type> // expected-error{{no type named}}
+  struct Inner1 { };
+  
+  template<T Value = X1<T>::value> // expected-error{{no member named 'value'}}
+  struct NonType1 { };
+  
+  template<T Value>
+  struct Inner2 { };
+  
+  template<typename U>
+  struct Inner3 {
+    template<typename X = T, typename V = U>
+    struct VeryInner { };
+    
+    template<T Value1 = sizeof(T), T Value2 = sizeof(U), 
+             T Value3 = Value1 + Value2>
+    struct NonType2 { };
+  };
+};
+
+X2<int> x2i;
+X2<int>::Inner1<float> x2iif;
+
+X2<int>::Inner1<> x2bad; // expected-note{{instantiation of default argument}}
+
+X2<int>::NonType1<'a'> x2_nontype1;
+X2<int>::NonType1<> x2_nontype1_bad; // expected-note{{instantiation of default argument}}
+
+// Check multi-level substitution into template type arguments
+X2<int>::Inner3<float>::VeryInner<> vi;
+X2<char>::Inner3<int>::NonType2<> x2_deep_nontype;
+
+
+template<typename T, typename U>
+struct is_same { static const bool value = false; };
+
+template<typename T>
+struct is_same<T, T> { static const bool value = true; };
+
+static int array1[is_same<__typeof__(vi), 
+               X2<int>::Inner3<float>::VeryInner<int, float> >::value? 1 : -1];
+
+static int array2[is_same<__typeof(x2_deep_nontype),
+                     X2<char>::Inner3<int>::NonType2<sizeof(char), sizeof(int), 
+                                    sizeof(char)+sizeof(int)> >::value? 1 : -1];





More information about the cfe-commits mailing list