diff --git a/Units/parser-cxx.r/template-member-function-pointer-scope.d/args.ctags b/Units/parser-cxx.r/template-member-function-pointer-scope.d/args.ctags new file mode 100644 index 0000000000..7d2ba98655 --- /dev/null +++ b/Units/parser-cxx.r/template-member-function-pointer-scope.d/args.ctags @@ -0,0 +1,3 @@ +--sort=no +--fields=+{signature} +--kinds-C++=+fstz diff --git a/Units/parser-cxx.r/template-member-function-pointer-scope.d/expected.tags b/Units/parser-cxx.r/template-member-function-pointer-scope.d/expected.tags new file mode 100644 index 0000000000..1ef6bca107 --- /dev/null +++ b/Units/parser-cxx.r/template-member-function-pointer-scope.d/expected.tags @@ -0,0 +1,19 @@ +TestUtil input.cpp /^struct TestUtil {$/;" s file: +isNull input.cpp /^ static bool isNull(const T&) { return false; }$/;" f struct:TestUtil typeref:typename:bool file: signature:(const T &) +__anon39cbdfcb010d input.cpp /^ static bool isNull(const T&) { return false; }$/;" z function:TestUtil::isNull typeref:typename:const T & file: +TestUtil input.cpp /^struct TestUtil {$/;" s file: +isNull input.cpp /^ static bool isNull(T* f) { return 0 == f; }$/;" f struct:TestUtil typeref:typename:bool file: signature:(T * f) +f input.cpp /^ static bool isNull(T* f) { return 0 == f; }$/;" z function:TestUtil::isNull typeref:typename:T * file: +memtype input.cpp /^struct memtype {};$/;" s file: +klass input.cpp /^struct klass {};$/;" s file: +isNull input.cpp /^TestUtil::isNull(const memtype klass::* &f)$/;" f class:TestUtil typeref:typename:bool signature:(const memtype klass::* & f) +f input.cpp /^TestUtil::isNull(const memtype klass::* &f)$/;" z function:TestUtil::isNull typeref:typename:const memtype klass::* & file: +Handler input.cpp /^struct Handler {$/;" s file: +process input.cpp /^ void process(T value) { }$/;" f struct:Handler typeref:typename:void file: signature:(T value) +value input.cpp /^ void process(T value) { }$/;" z function:Handler::process typeref:typename:T file: +Handler input.cpp /^struct Handler {$/;" s file: +process input.cpp /^ void process(R (C::*method)()) { }$/;" f struct:Handler typeref:typename:void file: signature:(R (C::* method)()) +method input.cpp /^ void process(R (C::*method)()) { }$/;" z function:Handler::process typeref:typename:R (C::*)() file: +Handler input.cpp /^struct Handler {$/;" s file: +process input.cpp /^ void process(R (C::*method)(A)) { }$/;" f struct:Handler typeref:typename:void file: signature:(R (C::* method)(A)) +method input.cpp /^ void process(R (C::*method)(A)) { }$/;" z function:Handler::process typeref:typename:R (C::*)(A) file: diff --git a/Units/parser-cxx.r/template-member-function-pointer-scope.d/input.cpp b/Units/parser-cxx.r/template-member-function-pointer-scope.d/input.cpp new file mode 100644 index 0000000000..9e0e7b08d5 --- /dev/null +++ b/Units/parser-cxx.r/template-member-function-pointer-scope.d/input.cpp @@ -0,0 +1,40 @@ +// Derived from #4348 submitted by @gaborbernat. + +// C++ template specialization that previously triggered scope management crash +// Test case for issue 4344: assertion failure in cxxScopePushTop +template +struct TestUtil { + static bool isNull(const T&) { return false; } +}; + +template +struct TestUtil { + static bool isNull(T* f) { return 0 == f; } +}; + +struct memtype {}; +struct klass {}; + +template <> +inline +bool +TestUtil::isNull(const memtype klass::* &f) +{ + return 0 == f; +} + +// Additional test cases for complex template specializations +template +struct Handler { + void process(T value) { } +}; + +template +struct Handler { + void process(R (C::*method)()) { } +}; + +template +struct Handler { + void process(R (C::*method)(A)) { } +}; diff --git a/Units/parser-cxx.r/template-member-function-pointer-scope.d/validator b/Units/parser-cxx.r/template-member-function-pointer-scope.d/validator new file mode 100644 index 0000000000..30c863ebde --- /dev/null +++ b/Units/parser-cxx.r/template-member-function-pointer-scope.d/validator @@ -0,0 +1 @@ +cxx11 diff --git a/Units/parser-cxx.r/template-specializations-including-op.d/args.ctags b/Units/parser-cxx.r/template-specializations-including-op.d/args.ctags new file mode 100644 index 0000000000..5ee5f79f70 --- /dev/null +++ b/Units/parser-cxx.r/template-specializations-including-op.d/args.ctags @@ -0,0 +1 @@ +--sort=no diff --git a/Units/parser-cxx.r/template-specializations-including-op.d/expected.tags b/Units/parser-cxx.r/template-specializations-including-op.d/expected.tags new file mode 100644 index 0000000000..0ea3085286 --- /dev/null +++ b/Units/parser-cxx.r/template-specializations-including-op.d/expected.tags @@ -0,0 +1,8 @@ +Point input.cpp /^struct Point {$/;" s file: +distance input.cpp /^ int distance(void) {$/;" f struct:Point typeref:typename:int file: +NS input.cpp /^namespace NS {$/;" n file: +MyReal input.cpp /^ using MyReal = float;$/;" t namespace:NS typeref:typename:float file: +MyVec input.cpp /^ using MyVec = T[2];$/;" t namespace:NS typeref:typename:T[2] file: +distance input.cpp /^int Point::distance(void) { return 1; }$/;" f class:Point typeref:typename:int +distance input.cpp /^int Point::distance(void) { return 1; }$/;" f class:Point typeref:typename:int +distance input.cpp /^int Point>::distance(void) { return 1; }$/;" f class:Point typeref:typename:int diff --git a/Units/parser-cxx.r/template-specializations-including-op.d/input.cpp b/Units/parser-cxx.r/template-specializations-including-op.d/input.cpp new file mode 100644 index 0000000000..7752ef75d5 --- /dev/null +++ b/Units/parser-cxx.r/template-specializations-including-op.d/input.cpp @@ -0,0 +1,21 @@ +template +struct Point { + int distance(void) { + return 0; + } +}; + +namespace NS { + using MyReal = float; + template + using MyVec = T[2]; +}; + +template<> +int Point::distance(void) { return 1; } + +template<> +int Point::distance(void) { return 1; } + +template<> +int Point>::distance(void) { return 1; } diff --git a/Units/parser-cxx.r/template-specializations-including-op.d/validator b/Units/parser-cxx.r/template-specializations-including-op.d/validator new file mode 100644 index 0000000000..30c863ebde --- /dev/null +++ b/Units/parser-cxx.r/template-specializations-including-op.d/validator @@ -0,0 +1 @@ +cxx11 diff --git a/parsers/cxx/cxx_parser_function.c b/parsers/cxx/cxx_parser_function.c index d8126019f3..ccbb872bd7 100644 --- a/parsers/cxx/cxx_parser_function.c +++ b/parsers/cxx/cxx_parser_function.c @@ -1591,10 +1591,37 @@ int cxxParserEmitFunctionTags( { CXXToken * pScopeId = pInfo->pScopeStart; - pInfo->pScopeStart = cxxTokenChainNextTokenOfType( + while (1) + { + pInfo->pScopeStart = cxxTokenChainNextTokenOfType( pInfo->pScopeStart, - CXXTokenTypeMultipleColons - ); + CXXTokenTypeMultipleColons|CXXTokenTypeSmallerThanSign); + + CXX_DEBUG_ASSERT(pInfo->pScopeStart, + "We could find neither '::' nor '<'"); + if (!pInfo->pScopeStart) + { + pInfo->pScopeStart = pInfo->pIdentifierStart; + break; + } + + if (cxxTokenTypeIs(pInfo->pScopeStart, CXXTokenTypeMultipleColons)) + break; // Good! + + if (cxxTokenTypeIs(pInfo->pScopeStart, CXXTokenTypeSmallerThanSign)) + { + // Skip the template arguments. + // Should we add the template arguments to the scope? (FIXME) + pInfo->pScopeStart = cxxTokenChainSkipToEndOfTemplateAngleBracket(pInfo->pScopeStart); + CXX_DEBUG_ASSERT(pInfo->pScopeStart, + "We could not find '>', the end of template argument(s)"); + if (!pInfo->pScopeStart) + { + pInfo->pScopeStart = pInfo->pIdentifierStart; + break; + } + } + } CXX_DEBUG_ASSERT(pInfo->pScopeStart,"We should have found a next token here");