Index: lib/Sema/SemaDecl.cpp =================================================================== --- lib/Sema/SemaDecl.cpp +++ lib/Sema/SemaDecl.cpp @@ -12181,7 +12181,7 @@ } Decl *Sema::ActOnSkippedFunctionBody(Decl *Decl) { - if (FunctionDecl *FD = dyn_cast_or_null(Decl)) + if (FunctionDecl *FD = Decl->getAsFunction()) FD->setHasSkippedBody(); else if (ObjCMethodDecl *MD = dyn_cast_or_null(Decl)) MD->setHasSkippedBody(); Index: lib/Sema/SemaTemplateInstantiateDecl.cpp =================================================================== --- lib/Sema/SemaTemplateInstantiateDecl.cpp +++ lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -3855,7 +3855,8 @@ } // Note, we should never try to instantiate a deleted function template. - assert((Pattern || PatternDecl->isDefaulted()) && + assert((Pattern || PatternDecl->isDefaulted() || + PatternDecl->hasSkippedBody()) && "unexpected kind of function template definition"); // C++1y [temp.explicit]p10: @@ -3940,16 +3941,20 @@ } } - // Instantiate the function body. - StmtResult Body = SubstStmt(Pattern, TemplateArgs); + if (PatternDecl->hasSkippedBody()) { + ActOnSkippedFunctionBody(Function); + } else { + // Instantiate the function body. + StmtResult Body = SubstStmt(Pattern, TemplateArgs); - if (Body.isInvalid()) - Function->setInvalidDecl(); + if (Body.isInvalid()) + Function->setInvalidDecl(); - // FIXME: finishing the function body while in an expression evaluation - // context seems wrong. Investigate more. - ActOnFinishFunctionBody(Function, Body.get(), - /*IsInstantiation=*/true); + // FIXME: finishing the function body while in an expression evaluation + // context seems wrong. Investigate more. + ActOnFinishFunctionBody(Function, Body.get(), + /*IsInstantiation=*/true); + } PerformDependentDiagnostics(PatternDecl, TemplateArgs); Index: test/Index/skipped-bodies-templates.cpp =================================================================== --- /dev/null +++ test/Index/skipped-bodies-templates.cpp @@ -0,0 +1,27 @@ +// RUN: env CINDEXTEST_SKIP_FUNCTION_BODIES=1 c-index-test -test-load-source all %s 2>&1 \ +// RUN: | FileCheck %s + + +template +struct Foo { + inline int with_body() { + return 100; + } + + inline int without_body(); +}; + + +int bar = Foo().with_body() + Foo().without_body(); +// CHECK-NOT: warning: inline function 'Foo::with_body' is not defined +// CHECK: warning: inline function 'Foo::without_body' is not defined + +template +inline int with_body() { return 10; } + +template +inline int without_body(); + +int baz = with_body() + without_body(); +// CHECK-NOT: warning: inline function 'with_body' is not defined +// CHECK: warning: inline function 'without_body' is not defined