r245810 - Instantiate function declarations in instantiated functions.

Serge Pavlov via cfe-commits cfe-commits at lists.llvm.org
Sun Aug 23 03:22:28 PDT 2015


Author: sepavloff
Date: Sun Aug 23 05:22:28 2015
New Revision: 245810

URL: http://llvm.org/viewvc/llvm-project?rev=245810&view=rev
Log:
Instantiate function declarations in instantiated functions.

If a function declaration is found inside a template function as in:

    template<class T> void f() {
      void g(int x = T::v) except(T::w);
    }

it must be instantiated along with the enclosing template function,
including default arguments and exception specification.

Together with the patch committed in r240974 this implements DR1484.

Differential Revision: http://reviews.llvm.org/D11194

Modified:
    cfe/trunk/include/clang/AST/DeclBase.h
    cfe/trunk/lib/AST/DeclBase.cpp
    cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
    cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
    cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/default-arguments.cpp
    cfe/trunk/test/SemaTemplate/default-arguments.cpp
    cfe/trunk/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp

Modified: cfe/trunk/include/clang/AST/DeclBase.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclBase.h?rev=245810&r1=245809&r2=245810&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclBase.h (original)
+++ cfe/trunk/include/clang/AST/DeclBase.h Sun Aug 23 05:22:28 2015
@@ -728,6 +728,15 @@ public:
     return getParentFunctionOrMethod() == nullptr;
   }
 
+  /// \brief Returns true if this declaration lexically is inside a function.
+  /// It recognizes non-defining declarations as well as members of local
+  /// classes:
+  /// \code
+  ///     void foo() { void bar(); }
+  ///     void foo2() { class ABC { void bar(); }; }
+  /// \endcode
+  bool isLexicallyWithinFunctionOrMethod() const;
+
   /// \brief If this decl is defined inside a function/method/block it returns
   /// the corresponding DeclContext, otherwise it returns null.
   const DeclContext *getParentFunctionOrMethod() const;

Modified: cfe/trunk/lib/AST/DeclBase.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclBase.cpp?rev=245810&r1=245809&r2=245810&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclBase.cpp (original)
+++ cfe/trunk/lib/AST/DeclBase.cpp Sun Aug 23 05:22:28 2015
@@ -266,6 +266,18 @@ void Decl::setDeclContextsImpl(DeclConte
   }
 }
 
+bool Decl::isLexicallyWithinFunctionOrMethod() const {
+  const DeclContext *LDC = getLexicalDeclContext();
+  do {
+    if (LDC->isFunctionOrMethod())
+      return true;
+    if (!isa<TagDecl>(LDC))
+      return false;
+    LDC = LDC->getParent();
+  } while (LDC);
+  return false;
+}
+
 bool Decl::isInAnonymousNamespace() const {
   const DeclContext *DC = getDeclContext();
   do {

Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp?rev=245810&r1=245809&r2=245810&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp Sun Aug 23 05:22:28 2015
@@ -1682,11 +1682,10 @@ ParmVarDecl *Sema::SubstParmVarDecl(Parm
     UnparsedDefaultArgInstantiations[OldParm].push_back(NewParm);
   } else if (Expr *Arg = OldParm->getDefaultArg()) {
     FunctionDecl *OwningFunc = cast<FunctionDecl>(OldParm->getDeclContext());
-    CXXRecordDecl *ClassD = dyn_cast<CXXRecordDecl>(OwningFunc->getDeclContext());
-    if (ClassD && ClassD->isLocalClass() && !ClassD->isLambda()) {
-      // If this is a method of a local class, as per DR1484 its default
-      // arguments must be instantiated.
-      Sema::ContextRAII SavedContext(*this, ClassD);
+    if (OwningFunc->isLexicallyWithinFunctionOrMethod()) {
+      // Instantiate default arguments for methods of local classes (DR1484)
+      // and non-defining declarations.
+      Sema::ContextRAII SavedContext(*this, OwningFunc);
       LocalInstantiationScope Local(*this);
       ExprResult NewArg = SubstExpr(Arg, TemplateArgs);
       if (NewArg.isUsable())

Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=245810&r1=245809&r2=245810&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Sun Aug 23 05:22:28 2015
@@ -3247,16 +3247,11 @@ TemplateDeclInstantiator::InitFunctionIn
     // exception specification.
     // DR1484: Local classes and their members are instantiated along with the
     // containing function.
-    bool RequireInstantiation = false;
-    if (CXXRecordDecl *Cls = dyn_cast<CXXRecordDecl>(Tmpl->getDeclContext())) {
-      if (Cls->isLocalClass())
-        RequireInstantiation = true;
-    }
     if (SemaRef.getLangOpts().CPlusPlus11 &&
         EPI.ExceptionSpec.Type != EST_None &&
         EPI.ExceptionSpec.Type != EST_DynamicNone &&
         EPI.ExceptionSpec.Type != EST_BasicNoexcept &&
-        !RequireInstantiation) {
+        !Tmpl->isLexicallyWithinFunctionOrMethod()) {
       FunctionDecl *ExceptionSpecTemplate = Tmpl;
       if (EPI.ExceptionSpec.Type == EST_Uninstantiated)
         ExceptionSpecTemplate = EPI.ExceptionSpec.SourceTemplate;

Modified: cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/default-arguments.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/default-arguments.cpp?rev=245810&r1=245809&r2=245810&view=diff
==============================================================================
--- cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/default-arguments.cpp (original)
+++ cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/default-arguments.cpp Sun Aug 23 05:22:28 2015
@@ -26,23 +26,26 @@ struct NonPOD {
 };
 
 struct NoDefaultCtor {
-  NoDefaultCtor(const NoDefaultCtor&); // expected-note{{candidate constructor}}
+  NoDefaultCtor(const NoDefaultCtor&); // expected-note{{candidate constructor}} \
+                                       // expected-note{{candidate constructor not viable: requires 1 argument, but 0 were provided}}
   ~NoDefaultCtor();
 };
 
 template<typename T>
 void defargs_in_template_unused(T t) {
-  auto l1 = [](const T& value = T()) { };
+  auto l1 = [](const T& value = T()) { };  // expected-error{{no matching constructor for initialization of 'NoDefaultCtor'}}
   l1(t);
 }
 
 template void defargs_in_template_unused(NonPOD);
-template void defargs_in_template_unused(NoDefaultCtor);
+template void defargs_in_template_unused(NoDefaultCtor);  // expected-note{{in instantiation of function template specialization 'defargs_in_template_unused<NoDefaultCtor>' requested here}}
 
 template<typename T>
 void defargs_in_template_used() {
-  auto l1 = [](const T& value = T()) { }; // expected-error{{no matching constructor for initialization of 'NoDefaultCtor'}}
-  l1(); // expected-note{{in instantiation of default function argument expression for 'operator()<NoDefaultCtor>' required here}}
+  auto l1 = [](const T& value = T()) { }; // expected-error{{no matching constructor for initialization of 'NoDefaultCtor'}} \
+                                          // expected-note{{candidate function not viable: requires single argument 'value', but no arguments were provided}} \
+                                          // expected-note{{conversion candidate of type 'void (*)(const NoDefaultCtor &)'}}
+  l1(); // expected-error{{no matching function for call to object of type '(lambda at }}
 }
 
 template void defargs_in_template_used<NonPOD>();

Modified: cfe/trunk/test/SemaTemplate/default-arguments.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/default-arguments.cpp?rev=245810&r1=245809&r2=245810&view=diff
==============================================================================
--- cfe/trunk/test/SemaTemplate/default-arguments.cpp (original)
+++ cfe/trunk/test/SemaTemplate/default-arguments.cpp Sun Aug 23 05:22:28 2015
@@ -159,3 +159,10 @@ namespace DR1635 {
 
   int g() { X<int>::f(0); } // expected-note {{in instantiation of template class 'DR1635::X<int>' requested here}}
 }
+
+namespace NondefDecls {
+  template<typename T> void f1() {
+    int g1(int defarg = T::error);  // expected-error{{type 'int' cannot be used prior to '::' because it has no members}}
+  }
+  template void f1<int>();  // expected-note{{in instantiation of function template specialization 'NondefDecls::f1<int>' requested here}}
+}

Modified: cfe/trunk/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp?rev=245810&r1=245809&r2=245810&view=diff
==============================================================================
--- cfe/trunk/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp (original)
+++ cfe/trunk/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp Sun Aug 23 05:22:28 2015
@@ -178,3 +178,11 @@ namespace Variadic {
   }
 
 }
+
+namespace NondefDecls {
+  template<typename T> void f1() {
+    int g1(int) noexcept(T::error); // expected-error{{type 'int' cannot be used prior to '::' because it has no members}}
+  }
+  template void f1<int>(); // expected-note{{in instantiation of function template specialization 'NondefDecls::f1<int>' requested here}}
+}
+




More information about the cfe-commits mailing list