This is an archive of the discontinued LLVM Phabricator instance.

Fix MSVC Compatibility around dependent type with missing 'typename'
AbandonedPublic

Authored by erichkeane on Feb 1 2017, 9:52 AM.

Details

Summary

As we know, MSVC is pretty relaxed when it comes to 'typename'. Clang so far does a pretty darn good job of permitting the behavior, however there was 1 missed case that compiles in MSVC (as of 2015), but not in clang. I've updated the test for similar ones that also/still pass, but were not tested.

template<typename T>
struct S { 
  typedef int TD;
};
template<class TMP>
void foo() {
  S<TMP>::TD varname =0;
}

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

The above was previously an error in clang in -fms-compatibility mode. This patch alters the parser in MSVC mode to correctly assume the 'typename' above where necessary.

Diff Detail

Event Timeline

erichkeane created this revision.Feb 1 2017, 9:52 AM

Some quick line-comments here.

lib/Parse/ParseStmt.cpp
186

Clang-tidy created this layout here that I'm not thrilled with, if OK, I'd like to move the entirety of the 2nd component to the "&&" on its own line. Additionally, if anyone has a better way to do this logic, I'm all ears!

test/SemaCXX/MicrosoftCompatibility.cpp
222

This is the line that previously failed. Curiously, the one above and below seemed to succeed without this change.

efriedma added inline comments.
lib/Parse/ParseStmt.cpp
186

Why is this checking for MSVCCompat? I think we want to detect constructs like your testcase in all modes so we can generate a good error message.

test/SemaCXX/MicrosoftCompatibility.cpp
222

The first one is obviously a declaration because of the "const" keyword, so we don't follow the same codepath. I would guess the last one hits the "Next.isNot(tok::coloncolon)" check in the if statment you're modifying.

A couple more related testcases:

A<T>::TYPE const var3 = 2; // const after type
A<T>::TYPE *var3 = 2; // we can't tell this is invalid until the template is instantiated
erichkeane added inline comments.Feb 16 2017, 10:58 AM
lib/Parse/ParseStmt.cpp
186

We get a good error message here ("typename missing") in normal mode. The issue here is that the examples below work in MSVC's relaxed 'typename' situation, thus this should only be accepting code in MSVC mode, right? Or am I missing something.

test/SemaCXX/MicrosoftCompatibility.cpp
222

Ah, right! I'll add those tests as well!

efriedma added inline comments.Feb 16 2017, 11:06 AM
lib/Parse/ParseStmt.cpp
186

This is what I see for the testcase in your commit message on trunk:

<stdin>:7:4: error: expected ';' after expression
  S<TMP>::TD varname =0;
   ^
   ;
<stdin>:7:14: error: use of undeclared identifier 'varname'
  S<TMP>::TD varname =0;
             ^
<stdin>:7:3: error: missing 'typename' prior to dependent type name 'S<int>::TD'
  S<TMP>::TD varname =0;
  ^~~~~~~~~~
<stdin>:11:3: note: in instantiation of function template specialization 'foo<int>' requested here
  foo<int>();
  ^
3 errors generated.

Technically speaking, we do get the "missing typename" message, but I still wouldn't call this result "a good error message".

erichkeane added inline comments.Feb 16 2017, 11:09 AM
lib/Parse/ParseStmt.cpp
186

Ah, I see! You're right, I got caught up in this a bunch. I'll look to see if I can get both cases to be better. Thanks!

Well hmm... changing this from MSVC to always caused a ton of regressions. I no longer think that this is a proper patch as it sits. Additionally, it doesn't fix the A<T>::TYPE *var3 condition.

erichkeane abandoned this revision.Apr 13 2017, 1:40 PM

I don't really see a good solution for this, and haven't tried in a while, so I'll see if I can prep another version of this in the future.