Index: include/clang/AST/DeclBase.h =================================================================== --- include/clang/AST/DeclBase.h +++ include/clang/AST/DeclBase.h @@ -728,6 +728,13 @@ return getParentFunctionOrMethod() == nullptr; } + /// \brief Returns true if this declaration lexically is inside a function. + /// In particular, it recognizes non-defining declarations such as: + /// \code + /// void foo() { 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; Index: lib/AST/DeclBase.cpp =================================================================== --- lib/AST/DeclBase.cpp +++ lib/AST/DeclBase.cpp @@ -266,6 +266,10 @@ } } +bool Decl::isLexicallyWithinFunctionOrMethod() const { + return getLexicalDeclContext()->isFunctionOrMethod(); +} + bool Decl::isInAnonymousNamespace() const { const DeclContext *DC = getDeclContext(); do { Index: lib/Sema/SemaDecl.cpp =================================================================== --- lib/Sema/SemaDecl.cpp +++ lib/Sema/SemaDecl.cpp @@ -1217,7 +1217,7 @@ if (getLangOpts().CPlusPlus && D->isOutOfLine() && !D->getDeclContext()->getRedeclContext()->Equals( D->getLexicalDeclContext()->getRedeclContext()) && - !D->getLexicalDeclContext()->isFunctionOrMethod()) + !D->isLexicallyWithinFunctionOrMethod()) return; // Template instantiations should also not be pushed into scope. @@ -3083,7 +3083,7 @@ // local declaration will produce a hard error; if it doesn't // remain visible, a single bogus local redeclaration (which is // actually only a warning) could break all the downstream code. - if (!New->getLexicalDeclContext()->isFunctionOrMethod()) + if (!New->isLexicallyWithinFunctionOrMethod()) New->getIdentifier()->revertBuiltin(); return false; @@ -3277,12 +3277,12 @@ // scope in which the bound was specified, an omitted array bound // is taken to be the same as in that earlier declaration. return NewVD->isPreviousDeclInSameBlockScope() || - (!OldVD->getLexicalDeclContext()->isFunctionOrMethod() && - !NewVD->getLexicalDeclContext()->isFunctionOrMethod()); + (!OldVD->isLexicallyWithinFunctionOrMethod() && + !NewVD->isLexicallyWithinFunctionOrMethod()); } else { // If the old declaration was function-local, don't merge with its // type unless we're in the same function. - return !OldVD->getLexicalDeclContext()->isFunctionOrMethod() || + return !OldVD->isLexicallyWithinFunctionOrMethod() || OldVD->getLexicalDeclContext() == NewVD->getLexicalDeclContext(); } } @@ -10437,7 +10437,7 @@ Prev; Prev = Prev->getPreviousDecl()) { // Ignore any declarations that occur in function or method // scope, because they aren't visible from the header. - if (Prev->getLexicalDeclContext()->isFunctionOrMethod()) + if (Prev->isLexicallyWithinFunctionOrMethod()) continue; MissingPrototype = !Prev->getType()->isFunctionProtoType(); Index: lib/Sema/SemaExpr.cpp =================================================================== --- lib/Sema/SemaExpr.cpp +++ lib/Sema/SemaExpr.cpp @@ -2716,7 +2716,7 @@ // turn off ADL anyway). if (isa(D)) D = cast(D)->getTargetDecl(); - else if (D->getLexicalDeclContext()->isFunctionOrMethod()) + else if (D->isLexicallyWithinFunctionOrMethod()) return false; // C++0x [basic.lookup.argdep]p3: Index: lib/Sema/SemaTemplateInstantiate.cpp =================================================================== --- lib/Sema/SemaTemplateInstantiate.cpp +++ lib/Sema/SemaTemplateInstantiate.cpp @@ -1691,6 +1691,16 @@ ExprResult NewArg = SubstExpr(Arg, TemplateArgs); if (NewArg.isUsable()) NewParm->setDefaultArg(NewArg.get()); + } else if (OwningFunc->isLexicallyWithinFunctionOrMethod()) { + // This is a function declaration within a function definition, as in: + // template void f() { + // void g(int x = T::v); + // } + Sema::ContextRAII SavedContext(*this, OwningFunc); + LocalInstantiationScope Local(*this); + ExprResult NewArg = SubstExpr(Arg, TemplateArgs); + if (NewArg.isUsable()) + NewParm->setDefaultArg(NewArg.get()); } else { // FIXME: if we non-lazily instantiated non-dependent default args for // non-dependent parameter types we could remove a bunch of duplicate Index: lib/Sema/SemaTemplateInstantiateDecl.cpp =================================================================== --- lib/Sema/SemaTemplateInstantiateDecl.cpp +++ lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -3250,6 +3250,9 @@ if (CXXRecordDecl *Cls = dyn_cast(Tmpl->getDeclContext())) { if (Cls->isLocalClass()) RequireInstantiation = true; + } else if (Tmpl->isLexicallyWithinFunctionOrMethod()) { + // This is a non-defining declaration of a file scope function. + RequireInstantiation = true; } if (SemaRef.getLangOpts().CPlusPlus11 && EPI.ExceptionSpec.Type != EST_None && Index: test/SemaTemplate/default-arguments.cpp =================================================================== --- test/SemaTemplate/default-arguments.cpp +++ test/SemaTemplate/default-arguments.cpp @@ -159,3 +159,10 @@ int g() { X::f(0); } // expected-note {{in instantiation of template class 'DR1635::X' requested here}} } + +namespace NondefDecls { + template 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(); // expected-note{{in instantiation of function template specialization 'NondefDecls::f1' requested here}} +} Index: test/SemaTemplate/instantiate-exception-spec-cxx11.cpp =================================================================== --- test/SemaTemplate/instantiate-exception-spec-cxx11.cpp +++ test/SemaTemplate/instantiate-exception-spec-cxx11.cpp @@ -178,3 +178,11 @@ } } + +namespace NondefDecls { + template 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(); // expected-note{{in instantiation of function template specialization 'NondefDecls::f1' requested here}} +} +