diff --git a/Units/parser-cxx.r/template-member-forward-declaration.d/args.ctags b/Units/parser-cxx.r/template-member-forward-declaration.d/args.ctags new file mode 100644 index 0000000000..0f72f99066 --- /dev/null +++ b/Units/parser-cxx.r/template-member-forward-declaration.d/args.ctags @@ -0,0 +1,2 @@ +--sort=no +--kinds-C++=m diff --git a/Units/parser-cxx.r/template-member-forward-declaration.d/expected.tags b/Units/parser-cxx.r/template-member-forward-declaration.d/expected.tags new file mode 100644 index 0000000000..b059cfeed8 --- /dev/null +++ b/Units/parser-cxx.r/template-member-forward-declaration.d/expected.tags @@ -0,0 +1,4 @@ +p input.cpp /^ Class *p;$/;" m class:A typeref:typename:Class * file: +a_c_forward input.cpp /^ A a_c_forward;$/;" m class:B typeref:typename:A file: +a_s_forward input.cpp /^ A a_s_forward;$/;" m class:B typeref:typename:A file: +a_u_forward input.cpp /^ A a_u_forward;$/;" m class:B typeref:typename:A file: diff --git a/Units/parser-cxx.r/template-member-forward-declaration.d/input.cpp b/Units/parser-cxx.r/template-member-forward-declaration.d/input.cpp new file mode 100644 index 0000000000..2c99009cbc --- /dev/null +++ b/Units/parser-cxx.r/template-member-forward-declaration.d/input.cpp @@ -0,0 +1,16 @@ +template +class A +{ +public: + A() { p = new Class(); } + Class *p; +}; + +class B { +public: + // forward declaration okay because only used as pointer in Template + A a_c_forward; + A a_s_forward; + A a_u_forward; +}; + diff --git a/parsers/cxx/cxx_parser_block.c b/parsers/cxx/cxx_parser_block.c index 0d6ea947d5..4eb8b02239 100644 --- a/parsers/cxx/cxx_parser_block.c +++ b/parsers/cxx/cxx_parser_block.c @@ -262,6 +262,7 @@ static bool cxxParserParseBlockInternal(bool bExpectClosingBracket) cppBeginStatement(); } + int iNestedAngleBracketLevel = 0; for(;;) { if(!cxxParserParseNextToken()) @@ -392,21 +393,24 @@ static bool cxxParserParseBlockInternal(bool bExpectClosingBracket) } break; case CXXKeywordCLASS: - if(!cxxParserParseClassStructOrUnion(CXXKeywordCLASS,CXXTagCPPKindCLASS,CXXScopeTypeClass)) + if(iNestedAngleBracketLevel == 0 && + !cxxParserParseClassStructOrUnion(CXXKeywordCLASS,CXXTagCPPKindCLASS,CXXScopeTypeClass)) { CXX_DEBUG_LEAVE_TEXT("Failed to parse class/struct/union"); return false; } break; case CXXKeywordSTRUCT: - if(!cxxParserParseClassStructOrUnion(CXXKeywordSTRUCT,CXXTagKindSTRUCT,CXXScopeTypeStruct)) + if(iNestedAngleBracketLevel == 0 && + !cxxParserParseClassStructOrUnion(CXXKeywordSTRUCT,CXXTagKindSTRUCT,CXXScopeTypeStruct)) { CXX_DEBUG_LEAVE_TEXT("Failed to parse class/struct/union"); return false; } break; case CXXKeywordUNION: - if(!cxxParserParseClassStructOrUnion(CXXKeywordUNION,CXXTagKindUNION,CXXScopeTypeUnion)) + if(iNestedAngleBracketLevel == 0 && + !cxxParserParseClassStructOrUnion(CXXKeywordUNION,CXXTagKindUNION,CXXScopeTypeUnion)) { CXX_DEBUG_LEAVE_TEXT("Failed to parse class/struct/union"); return false; @@ -744,6 +748,12 @@ static bool cxxParserParseBlockInternal(bool bExpectClosingBracket) else if (cxxScopeGetType() == CXXScopeTypeClass) cxxSubparserUnknownIdentifierInClassNotify(g_cxx.pToken); break; + case CXXTokenTypeSmallerThanSign: + iNestedAngleBracketLevel++; + break; + case CXXTokenTypeGreaterThanSign: + iNestedAngleBracketLevel--; + break; default: // something else we didn't handle break;