MS-Incompatibility regarding "typename" in dependent context

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

MS-Incompatibility regarding "typename" in dependent context

Roman Popov via cfe-dev
I'm currently working on a MS compatibility bug that I am pretty stuck with, that I was hoping someone could give me a hand on how to figure out.  This is currently blocking MySQL from building in MS compatibility mode.  First, the reproducer:

template<class T> struct Struct{
  typedef int TypeDef;
};

template<class TMP> void foo() {
  Struct<TMP>::TypeDef varname;
}

void foo2()
{
  foo<int>();
}

The result is:
typename_test.cpp:8:9: error: expected ';' after expression
  Struct<TMP>::TypeDef varname;

This is due to Parser::ParseStatementOrDeclarationAfterAttributes (ParseStmt.cpp:152) deciding that it is an expression.  I've dug into this, and I see it go into the case tok::identifier's branch "Next.isNot(tok::coloncolon)".  Inside that, TryAnnotateName annotates the Tok token as "annot_primary_expr".  

I would expect it to be annot_typename or something similar, such that the call to isCXXDeclarationSpecifier (via isDeclarationStatement()) succeeds.

So I guess my question is:  Am I better off trying to comprehend this functionality in TryAnnotateName, or just alter isCXXDeclarationSpecifier to give a different answer?  Is there a better option that I'm missing?

Also, can anyone give me a tip on how to begin with either?  I'm in a little bit of a foreign land attempting to mess with parsing this much.

Thanks,
Erich
_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: MS-Incompatibility regarding "typename" in dependent context

Roman Popov via cfe-dev
On 1/31/2017 3:55 PM, Keane, Erich via cfe-dev wrote:

> I'm currently working on a MS compatibility bug that I am pretty stuck with, that I was hoping someone could give me a hand on how to figure out.  This is currently blocking MySQL from building in MS compatibility mode.  First, the reproducer:
>
> template<class T> struct Struct{
>    typedef int TypeDef;
> };
>
> template<class TMP> void foo() {
>    Struct<TMP>::TypeDef varname;
> }
>
> void foo2()
> {
>    foo<int>();
> }
>
> The result is:
> typename_test.cpp:8:9: error: expected ';' after expression
>    Struct<TMP>::TypeDef varname;
>
> This is due to Parser::ParseStatementOrDeclarationAfterAttributes (ParseStmt.cpp:152) deciding that it is an expression.  I've dug into this, and I see it go into the case tok::identifier's branch "Next.isNot(tok::coloncolon)".  Inside that, TryAnnotateName annotates the Tok token as "annot_primary_expr".
>
> I would expect it to be annot_typename or something similar, such that the call to isCXXDeclarationSpecifier (via isDeclarationStatement()) succeeds.

If you assume the code is well-formed, and see just the tokens
"Struct<TMP>::TypeDef", it's pretty clearly not a typename according to
normal C++ parsing rules.  Of course, your testcase isn't well-formed,
so you want to look ahead, figure out that "Struct<TMP>::TypeDef
varname" can't be an expression, then print a diagnostic and force
"Struct<TMP>::TypeDef" to parse as a type.
> So I guess my question is:  Am I better off trying to comprehend this functionality in TryAnnotateName, or just alter isCXXDeclarationSpecifier to give a different answer?  Is there a better option that I'm missing?

If you change "Next.isNot(tok::coloncolon)" to
"Next.isNot(tok::coloncolon) && Next.isNot(tok::less)", it throws you
onto the right codepath for your testcase.  I'm not sure that's
precisely what you want, but maybe a start.

-Eli

--
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project

_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: MS-Incompatibility regarding "typename" in dependent context

Roman Popov via cfe-dev
Ah, wow, thank you very much!

My code example compiles in MSVC due to the messed up 'typename' rules, so I am trying to more appropriately match that functionality.

I was running down "TryAnnotateName" for a while, and discovered that if "ClassifyName" returns NC_TypeTemplate, everything works too.  However, it seems like I can get the same result with your suggested change!

I'll continue working on this to get it to be a MSVC option only  and do my best to validate the use case.

Thanks again!
-Erich

-----Original Message-----
From: Friedman, Eli [mailto:[hidden email]]
Sent: Tuesday, January 31, 2017 4:55 PM
To: Keane, Erich <[hidden email]>; cfe-dev <[hidden email]>
Subject: Re: [cfe-dev] MS-Incompatibility regarding "typename" in dependent context

On 1/31/2017 3:55 PM, Keane, Erich via cfe-dev wrote:

> I'm currently working on a MS compatibility bug that I am pretty stuck with, that I was hoping someone could give me a hand on how to figure out.  This is currently blocking MySQL from building in MS compatibility mode.  First, the reproducer:
>
> template<class T> struct Struct{
>    typedef int TypeDef;
> };
>
> template<class TMP> void foo() {
>    Struct<TMP>::TypeDef varname;
> }
>
> void foo2()
> {
>    foo<int>();
> }
>
> The result is:
> typename_test.cpp:8:9: error: expected ';' after expression
>    Struct<TMP>::TypeDef varname;
>
> This is due to Parser::ParseStatementOrDeclarationAfterAttributes (ParseStmt.cpp:152) deciding that it is an expression.  I've dug into this, and I see it go into the case tok::identifier's branch "Next.isNot(tok::coloncolon)".  Inside that, TryAnnotateName annotates the Tok token as "annot_primary_expr".
>
> I would expect it to be annot_typename or something similar, such that the call to isCXXDeclarationSpecifier (via isDeclarationStatement()) succeeds.

If you assume the code is well-formed, and see just the tokens "Struct<TMP>::TypeDef", it's pretty clearly not a typename according to normal C++ parsing rules.  Of course, your testcase isn't well-formed, so you want to look ahead, figure out that "Struct<TMP>::TypeDef varname" can't be an expression, then print a diagnostic and force "Struct<TMP>::TypeDef" to parse as a type.
> So I guess my question is:  Am I better off trying to comprehend this functionality in TryAnnotateName, or just alter isCXXDeclarationSpecifier to give a different answer?  Is there a better option that I'm missing?

If you change "Next.isNot(tok::coloncolon)" to
"Next.isNot(tok::coloncolon) && Next.isNot(tok::less)", it throws you onto the right codepath for your testcase.  I'm not sure that's precisely what you want, but maybe a start.

-Eli

--
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project

_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev