[PATCH] D29868: Recover more gracefully when __declspec is not supported as a keyword

2017-02-14 Thread Aaron Ballman via Phabricator via cfe-commits
aaron.ballman closed this revision.
aaron.ballman added a comment.

Commit in r295114.


https://reviews.llvm.org/D29868



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D29868: Recover more gracefully when __declspec is not supported as a keyword

2017-02-13 Thread David Majnemer via Phabricator via cfe-commits
majnemer added inline comments.



Comment at: lib/Parse/ParseDecl.cpp:2989
+
+  Diag(Loc, diag::err_ms_attributes_not_enabled);
+  continue;

aaron.ballman wrote:
> majnemer wrote:
> > aaron.ballman wrote:
> > > compnerd wrote:
> > > > aaron.ballman wrote:
> > > > > compnerd wrote:
> > > > > > I think that we want to emit the diagnostic even if there is no 
> > > > > > parenthesis as `__declspec` is a reserved identifier, and we would 
> > > > > > normally diagnose the bad `__declspec` (expected '(' after 
> > > > > > '__declspec').
> > > > > Yes, but it could also lead to a rejecting code that we used to 
> > > > > accept and properly handle when __declspec is an identifier rather 
> > > > > than a keyword. e.g.,
> > > > > ```
> > > > > struct __declspec {};
> > > > > 
> > > > > __declspec some_func(void);
> > > > > ```
> > > > > By looking for the paren, we run less risk of breaking working code, 
> > > > > even if that code abuses the implementation namespace (after all, 
> > > > > __declspec it not a keyword in this scenario).
> > > > But we would reject that code under `-fdeclspec` anyways.  I think 
> > > > having the code be more portable is a bit nicer.
> > > After discussing in IRC, I decided that I agree with @compnerd on this 
> > > and have changed the patch accordingly.
> > What if somebody wants to use __declspec and are using the compiler in a 
> > freestanding mode? Also, we aren't the only member of the implementor's 
> > namespace.
> Users using __declspec in a freestanding mode is a concern that I share. 
> However, I imagine there are *far* more users who accidentally forget to pass 
> `-fdeclspec` than there are users who are writing code in freestanding mode 
> that wish to use `__declspec` as an identifier in a situation that proves 
> problematic. That being said, do you think the approach in the patch would 
> work with a warning rather than an error? I went with an error because I felt 
> that a warning would require tentative parsing to be properly implemented, 
> which felt like a heavy solution for a problem I didn't think anyone would 
> run into in practice.
> 
> I'm not overly sympathetic to others in the implementor's namespace who use 
> `__declspec` but not to implement attributes under that name. However, I 
> could be convinced to be sympathetic if there was some conflict in practice. 
> Do you have a case in mind?
I suppose what you've got should be fine in practice. Heck, we used to have 
__declspec attributes available all the time...


https://reviews.llvm.org/D29868



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D29868: Recover more gracefully when __declspec is not supported as a keyword

2017-02-13 Thread Aaron Ballman via Phabricator via cfe-commits
aaron.ballman marked an inline comment as done.
aaron.ballman added inline comments.



Comment at: lib/Parse/ParseDecl.cpp:2989
+
+  Diag(Loc, diag::err_ms_attributes_not_enabled);
+  continue;

majnemer wrote:
> aaron.ballman wrote:
> > compnerd wrote:
> > > aaron.ballman wrote:
> > > > compnerd wrote:
> > > > > I think that we want to emit the diagnostic even if there is no 
> > > > > parenthesis as `__declspec` is a reserved identifier, and we would 
> > > > > normally diagnose the bad `__declspec` (expected '(' after 
> > > > > '__declspec').
> > > > Yes, but it could also lead to a rejecting code that we used to accept 
> > > > and properly handle when __declspec is an identifier rather than a 
> > > > keyword. e.g.,
> > > > ```
> > > > struct __declspec {};
> > > > 
> > > > __declspec some_func(void);
> > > > ```
> > > > By looking for the paren, we run less risk of breaking working code, 
> > > > even if that code abuses the implementation namespace (after all, 
> > > > __declspec it not a keyword in this scenario).
> > > But we would reject that code under `-fdeclspec` anyways.  I think having 
> > > the code be more portable is a bit nicer.
> > After discussing in IRC, I decided that I agree with @compnerd on this and 
> > have changed the patch accordingly.
> What if somebody wants to use __declspec and are using the compiler in a 
> freestanding mode? Also, we aren't the only member of the implementor's 
> namespace.
Users using __declspec in a freestanding mode is a concern that I share. 
However, I imagine there are *far* more users who accidentally forget to pass 
`-fdeclspec` than there are users who are writing code in freestanding mode 
that wish to use `__declspec` as an identifier in a situation that proves 
problematic. That being said, do you think the approach in the patch would work 
with a warning rather than an error? I went with an error because I felt that a 
warning would require tentative parsing to be properly implemented, which felt 
like a heavy solution for a problem I didn't think anyone would run into in 
practice.

I'm not overly sympathetic to others in the implementor's namespace who use 
`__declspec` but not to implement attributes under that name. However, I could 
be convinced to be sympathetic if there was some conflict in practice. Do you 
have a case in mind?


https://reviews.llvm.org/D29868



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D29868: Recover more gracefully when __declspec is not supported as a keyword

2017-02-13 Thread David Majnemer via Phabricator via cfe-commits
majnemer added inline comments.



Comment at: lib/Parse/ParseDecl.cpp:2989
+
+  Diag(Loc, diag::err_ms_attributes_not_enabled);
+  continue;

aaron.ballman wrote:
> compnerd wrote:
> > aaron.ballman wrote:
> > > compnerd wrote:
> > > > I think that we want to emit the diagnostic even if there is no 
> > > > parenthesis as `__declspec` is a reserved identifier, and we would 
> > > > normally diagnose the bad `__declspec` (expected '(' after 
> > > > '__declspec').
> > > Yes, but it could also lead to a rejecting code that we used to accept 
> > > and properly handle when __declspec is an identifier rather than a 
> > > keyword. e.g.,
> > > ```
> > > struct __declspec {};
> > > 
> > > __declspec some_func(void);
> > > ```
> > > By looking for the paren, we run less risk of breaking working code, even 
> > > if that code abuses the implementation namespace (after all, __declspec 
> > > it not a keyword in this scenario).
> > But we would reject that code under `-fdeclspec` anyways.  I think having 
> > the code be more portable is a bit nicer.
> After discussing in IRC, I decided that I agree with @compnerd on this and 
> have changed the patch accordingly.
What if somebody wants to use __declspec and are using the compiler in a 
freestanding mode? Also, we aren't the only member of the implementor's 
namespace.


https://reviews.llvm.org/D29868



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D29868: Recover more gracefully when __declspec is not supported as a keyword

2017-02-13 Thread Aaron Ballman via Phabricator via cfe-commits
aaron.ballman marked 3 inline comments as done.
aaron.ballman added inline comments.



Comment at: lib/Parse/ParseDecl.cpp:2989
+
+  Diag(Loc, diag::err_ms_attributes_not_enabled);
+  continue;

compnerd wrote:
> aaron.ballman wrote:
> > compnerd wrote:
> > > I think that we want to emit the diagnostic even if there is no 
> > > parenthesis as `__declspec` is a reserved identifier, and we would 
> > > normally diagnose the bad `__declspec` (expected '(' after '__declspec').
> > Yes, but it could also lead to a rejecting code that we used to accept and 
> > properly handle when __declspec is an identifier rather than a keyword. 
> > e.g.,
> > ```
> > struct __declspec {};
> > 
> > __declspec some_func(void);
> > ```
> > By looking for the paren, we run less risk of breaking working code, even 
> > if that code abuses the implementation namespace (after all, __declspec it 
> > not a keyword in this scenario).
> But we would reject that code under `-fdeclspec` anyways.  I think having the 
> code be more portable is a bit nicer.
After discussing in IRC, I decided that I agree with @compnerd on this and have 
changed the patch accordingly.


https://reviews.llvm.org/D29868



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D29868: Recover more gracefully when __declspec is not supported as a keyword

2017-02-13 Thread Aaron Ballman via Phabricator via cfe-commits
aaron.ballman updated this revision to Diff 88198.
aaron.ballman added a comment.

Fixed review feedback


https://reviews.llvm.org/D29868

Files:
  include/clang/Basic/DiagnosticParseKinds.td
  lib/Parse/ParseDecl.cpp
  test/Parser/declspec-recovery.c
  test/Parser/declspec-supported.c


Index: test/Parser/declspec-supported.c
===
--- test/Parser/declspec-supported.c
+++ test/Parser/declspec-supported.c
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -triple i386-pc-unknown -fsyntax-only -fms-extensions 
-verify %s
+// RUN: %clang_cc1 -triple i386-pc-unknown -fsyntax-only -fdeclspec -verify %s
+// expected-no-diagnostics
+
+__declspec(naked) void f(void) {}
+
+struct S {
+  __declspec(property(get=Getter, put=Setter)) int X;
+  int Y;
+};
Index: test/Parser/declspec-recovery.c
===
--- test/Parser/declspec-recovery.c
+++ test/Parser/declspec-recovery.c
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -triple i386-pc-unknown -fsyntax-only -verify %s
+
+__declspec(naked) void f(void) {} // expected-error{{'__declspec' attributes 
are not enabled; use '-fdeclspec' or '-fms-extensions' to enable support for 
__declspec attributes}}
+
+struct S {
+  __declspec(property(get=Getter, put=Setter)) int X; // 
expected-error{{'__declspec' attributes are not enabled; use '-fdeclspec' or 
'-fms-extensions' to enable support for __declspec attributes}}
+  int Y;
+};
Index: lib/Parse/ParseDecl.cpp
===
--- lib/Parse/ParseDecl.cpp
+++ lib/Parse/ParseDecl.cpp
@@ -2966,6 +2966,31 @@
   if (DS.hasTypeSpecifier())
 goto DoneWithDeclSpec;
 
+  // If the token is an identifier named "__declspec" and Microsoft
+  // extensions are not enabled, it is likely that there will be cascading
+  // parse errors if this really is a __declspec attribute. Attempt to
+  // recognize that scenario and recover gracefully.
+  if (!getLangOpts().DeclSpecKeyword && Tok.is(tok::identifier) &&
+  Tok.getIdentifierInfo()->getName().equals("__declspec")) {
+Diag(Loc, diag::err_ms_attributes_not_enabled);
+
+// The next token should be an open paren. If it is, eat the entire
+// attribute declaration and continue.
+if (NextToken().is(tok::l_paren)) {
+  // Consume the __declspec identifier.
+  SourceLocation Loc = ConsumeToken();
+
+  // Eat the parens and everything between them.
+  BalancedDelimiterTracker T(*this, tok::l_paren);
+  if (T.consumeOpen()) {
+assert(false && "Not a left paren?");
+return;
+  }
+  T.skipToEnd();
+  continue;
+}
+  }
+
   // In C++, check to see if this is a scope specifier like foo::bar::, if
   // so handle it as such.  This is important for ctor parsing.
   if (getLangOpts().CPlusPlus) {
Index: include/clang/Basic/DiagnosticParseKinds.td
===
--- include/clang/Basic/DiagnosticParseKinds.td
+++ include/clang/Basic/DiagnosticParseKinds.td
@@ -176,6 +176,9 @@
 def warn_attribute_no_decl : Warning<
   "attribute %0 ignored, because it is not attached to a declaration">, 
   InGroup;
+def err_ms_attributes_not_enabled : Error<
+  "'__declspec' attributes are not enabled; use '-fdeclspec' or "
+  "'-fms-extensions' to enable support for __declspec attributes">;
 def err_expected_method_body : Error<"expected method body">;
 def err_declspec_after_virtspec : Error<
   "'%0' qualifier may not appear after the virtual specifier '%1'">;


Index: test/Parser/declspec-supported.c
===
--- test/Parser/declspec-supported.c
+++ test/Parser/declspec-supported.c
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -triple i386-pc-unknown -fsyntax-only -fms-extensions -verify %s
+// RUN: %clang_cc1 -triple i386-pc-unknown -fsyntax-only -fdeclspec -verify %s
+// expected-no-diagnostics
+
+__declspec(naked) void f(void) {}
+
+struct S {
+  __declspec(property(get=Getter, put=Setter)) int X;
+  int Y;
+};
Index: test/Parser/declspec-recovery.c
===
--- test/Parser/declspec-recovery.c
+++ test/Parser/declspec-recovery.c
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -triple i386-pc-unknown -fsyntax-only -verify %s
+
+__declspec(naked) void f(void) {} // expected-error{{'__declspec' attributes are not enabled; use '-fdeclspec' or '-fms-extensions' to enable support for __declspec attributes}}
+
+struct S {
+  __declspec(property(get=Getter, put=Setter)) int X; // expected-error{{'__declspec' attributes are not enabled; use '-fdeclspec' or '-fms-extensions' to enable support for __declspec attributes}}
+  int Y;
+};
Index: lib/Parse/ParseDecl.cpp
===
--- 

[PATCH] D29868: Recover more gracefully when __declspec is not supported as a keyword

2017-02-12 Thread Saleem Abdulrasool via Phabricator via cfe-commits
compnerd added inline comments.



Comment at: lib/Parse/ParseDecl.cpp:2989
+
+  Diag(Loc, diag::err_ms_attributes_not_enabled);
+  continue;

aaron.ballman wrote:
> compnerd wrote:
> > I think that we want to emit the diagnostic even if there is no parenthesis 
> > as `__declspec` is a reserved identifier, and we would normally diagnose 
> > the bad `__declspec` (expected '(' after '__declspec').
> Yes, but it could also lead to a rejecting code that we used to accept and 
> properly handle when __declspec is an identifier rather than a keyword. e.g.,
> ```
> struct __declspec {};
> 
> __declspec some_func(void);
> ```
> By looking for the paren, we run less risk of breaking working code, even if 
> that code abuses the implementation namespace (after all, __declspec it not a 
> keyword in this scenario).
But we would reject that code under `-fdeclspec` anyways.  I think having the 
code be more portable is a bit nicer.


https://reviews.llvm.org/D29868



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D29868: Recover more gracefully when __declspec is not supported as a keyword

2017-02-12 Thread Aaron Ballman via Phabricator via cfe-commits
aaron.ballman added inline comments.



Comment at: lib/Parse/ParseDecl.cpp:2973
+  // recognize that scenario and recover gracefully.
+  if (!getLangOpts().MicrosoftExt && Tok.is(tok::identifier) &&
+  Tok.getIdentifierInfo()->getName().equals("__declspec")) {

compnerd wrote:
> Shouldn't this be `getLangOpts().DeclSpecKeyword` since you don't need the 
> Microsoft extensions as much as you need the declspec keyword to be 
> processed.  Having `MicrosoftExt` implicitly enable `DeclSpecKeyword` (just 
> as borland mode enables it as well).  I suppose that it would fail anyways as 
> `Tok.is(tok::identifier)` would fail.
That's a good point, I've corrected.



Comment at: lib/Parse/ParseDecl.cpp:2989
+
+  Diag(Loc, diag::err_ms_attributes_not_enabled);
+  continue;

compnerd wrote:
> I think that we want to emit the diagnostic even if there is no parenthesis 
> as `__declspec` is a reserved identifier, and we would normally diagnose the 
> bad `__declspec` (expected '(' after '__declspec').
Yes, but it could also lead to a rejecting code that we used to accept and 
properly handle when __declspec is an identifier rather than a keyword. e.g.,
```
struct __declspec {};

__declspec some_func(void);
```
By looking for the paren, we run less risk of breaking working code, even if 
that code abuses the implementation namespace (after all, __declspec it not a 
keyword in this scenario).


https://reviews.llvm.org/D29868



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D29868: Recover more gracefully when __declspec is not supported as a keyword

2017-02-12 Thread Aaron Ballman via Phabricator via cfe-commits
aaron.ballman updated this revision to Diff 88122.
aaron.ballman marked an inline comment as done.
aaron.ballman added a comment.

Correcting review feedback.


https://reviews.llvm.org/D29868

Files:
  include/clang/Basic/DiagnosticParseKinds.td
  lib/Parse/ParseDecl.cpp
  test/Parser/declspec-recovery.c
  test/Parser/declspec-supported.c


Index: test/Parser/declspec-supported.c
===
--- test/Parser/declspec-supported.c
+++ test/Parser/declspec-supported.c
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -triple i386-pc-unknown -fsyntax-only -fms-extensions 
-verify %s
+// RUN: %clang_cc1 -triple i386-pc-unknown -fsyntax-only -fdeclspec -verify %s
+// expected-no-diagnostics
+
+__declspec(naked) void f(void) {}
+
+struct S {
+  __declspec(property(get=Getter, put=Setter)) int X;
+  int Y;
+};
Index: test/Parser/declspec-recovery.c
===
--- test/Parser/declspec-recovery.c
+++ test/Parser/declspec-recovery.c
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -triple i386-pc-unknown -fsyntax-only -verify %s
+
+__declspec(naked) void f(void) {} // expected-error{{'__declspec' attributes 
are not enabled; use '-fdeclspec' or '-fms-extensions' to enable support for 
__declspec attributes}}
+
+struct S {
+  __declspec(property(get=Getter, put=Setter)) int X; // 
expected-error{{'__declspec' attributes are not enabled; use '-fdeclspec' or 
'-fms-extensions' to enable support for __declspec attributes}}
+  int Y;
+};
Index: lib/Parse/ParseDecl.cpp
===
--- lib/Parse/ParseDecl.cpp
+++ lib/Parse/ParseDecl.cpp
@@ -2966,6 +2966,31 @@
   if (DS.hasTypeSpecifier())
 goto DoneWithDeclSpec;
 
+  // If the token is an identifier named "__declspec" and Microsoft
+  // extensions are not enabled, it is likely that there will be cascading
+  // parse errors if this really is a __declspec attribute. Attempt to
+  // recognize that scenario and recover gracefully.
+  if (!getLangOpts().DeclSpecKeyword && Tok.is(tok::identifier) &&
+  Tok.getIdentifierInfo()->getName().equals("__declspec")) {
+// The next token should be an open paren. If it is, eat the entire
+// attribute declaration and continue.
+if (NextToken().is(tok::l_paren)) {
+  // Consume the __declspec identifier.
+  SourceLocation Loc = ConsumeToken();
+
+  // Eat the parens and everything between them.
+  BalancedDelimiterTracker T(*this, tok::l_paren);
+  if (T.consumeOpen()) {
+assert(false && "Not a left paren?");
+return;
+  }
+  T.skipToEnd();
+
+  Diag(Loc, diag::err_ms_attributes_not_enabled);
+  continue;
+}
+  }
+
   // In C++, check to see if this is a scope specifier like foo::bar::, if
   // so handle it as such.  This is important for ctor parsing.
   if (getLangOpts().CPlusPlus) {
Index: include/clang/Basic/DiagnosticParseKinds.td
===
--- include/clang/Basic/DiagnosticParseKinds.td
+++ include/clang/Basic/DiagnosticParseKinds.td
@@ -176,6 +176,9 @@
 def warn_attribute_no_decl : Warning<
   "attribute %0 ignored, because it is not attached to a declaration">, 
   InGroup;
+def err_ms_attributes_not_enabled : Error<
+  "'__declspec' attributes are not enabled; use '-fdeclspec' or "
+  "'-fms-extensions' to enable support for __declspec attributes">;
 def err_expected_method_body : Error<"expected method body">;
 def err_declspec_after_virtspec : Error<
   "'%0' qualifier may not appear after the virtual specifier '%1'">;


Index: test/Parser/declspec-supported.c
===
--- test/Parser/declspec-supported.c
+++ test/Parser/declspec-supported.c
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -triple i386-pc-unknown -fsyntax-only -fms-extensions -verify %s
+// RUN: %clang_cc1 -triple i386-pc-unknown -fsyntax-only -fdeclspec -verify %s
+// expected-no-diagnostics
+
+__declspec(naked) void f(void) {}
+
+struct S {
+  __declspec(property(get=Getter, put=Setter)) int X;
+  int Y;
+};
Index: test/Parser/declspec-recovery.c
===
--- test/Parser/declspec-recovery.c
+++ test/Parser/declspec-recovery.c
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -triple i386-pc-unknown -fsyntax-only -verify %s
+
+__declspec(naked) void f(void) {} // expected-error{{'__declspec' attributes are not enabled; use '-fdeclspec' or '-fms-extensions' to enable support for __declspec attributes}}
+
+struct S {
+  __declspec(property(get=Getter, put=Setter)) int X; // expected-error{{'__declspec' attributes are not enabled; use '-fdeclspec' or '-fms-extensions' to enable support for __declspec attributes}}
+  int Y;
+};
Index: lib/Parse/ParseDecl.cpp

[PATCH] D29868: Recover more gracefully when __declspec is not supported as a keyword

2017-02-11 Thread Saleem Abdulrasool via Phabricator via cfe-commits
compnerd added inline comments.



Comment at: lib/Parse/ParseDecl.cpp:2973
+  // recognize that scenario and recover gracefully.
+  if (!getLangOpts().MicrosoftExt && Tok.is(tok::identifier) &&
+  Tok.getIdentifierInfo()->getName().equals("__declspec")) {

Shouldn't this be `getLangOpts().DeclSpecKeyword` since you don't need the 
Microsoft extensions as much as you need the declspec keyword to be processed.  
Having `MicrosoftExt` implicitly enable `DeclSpecKeyword` (just as borland mode 
enables it as well).  I suppose that it would fail anyways as 
`Tok.is(tok::identifier)` would fail.



Comment at: lib/Parse/ParseDecl.cpp:2989
+
+  Diag(Loc, diag::err_ms_attributes_not_enabled);
+  continue;

I think that we want to emit the diagnostic even if there is no parenthesis as 
`__declspec` is a reserved identifier, and we would normally diagnose the bad 
`__declspec` (expected '(' after '__declspec').


https://reviews.llvm.org/D29868



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D29868: Recover more gracefully when __declspec is not supported as a keyword

2017-02-11 Thread Aaron Ballman via Phabricator via cfe-commits
aaron.ballman created this revision.

In r238238, we removed __declspec as a universally-accepted keyword -- instead, 
it is only enabled as a supported keyword when -fms-extensions or -fdeclspec is 
passed to the driver. However, this had an unfortunate side-effect in that it 
made for bad diagnostics in the presence of a __declspec when neither of those 
flags are passed. For instance:

__declspec(naked) void f(void) {}

clang -fsyntax-only -fno-ms-extensions -Wall -pedantic main.c

main.cpp:1:24: error: parameter named 'f' is missing
__declspec(naked) void f(void) {}

  ^

main.cpp:1:31: error: expected ';' at end of declaration
__declspec(naked) void f(void) {}

  ^
  ;

main.cpp:1:12: warning: parameter 'naked' was not declared, defaulting to type 
'int' [-Wpedantic]
__declspec(naked) void f(void) {}

  ^

main.cpp:1:1: warning: type specifier missing, defaults to 'int' 
[-Wimplicit-int]
__declspec(naked) void f(void) {}

This patch addresses the poor diagnostics by noticing when a __declspec has 
been used but is not enabled. It eats the attribute, diagnoses the use, and 
then attempts to continue parsing.


https://reviews.llvm.org/D29868

Files:
  include/clang/Basic/DiagnosticParseKinds.td
  lib/Parse/ParseDecl.cpp
  test/Parser/declspec-recovery.c
  test/Parser/declspec-supported.c


Index: test/Parser/declspec-supported.c
===
--- test/Parser/declspec-supported.c
+++ test/Parser/declspec-supported.c
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -triple i386-pc-unknown -fsyntax-only -fms-extensions 
-verify %s
+// RUN: %clang_cc1 -triple i386-pc-unknown -fsyntax-only -fdeclspec -verify %s
+// expected-no-diagnostics
+
+__declspec(naked) void f(void) {}
+
+struct S {
+  __declspec(property(get=Getter, put=Setter)) int X;
+  int Y;
+};
Index: test/Parser/declspec-recovery.c
===
--- test/Parser/declspec-recovery.c
+++ test/Parser/declspec-recovery.c
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -triple i386-pc-unknown -fsyntax-only -verify %s
+
+__declspec(naked) void f(void) {} // expected-error{{'__declspec' attributes 
are not enabled; use '-fdeclspec' or '-fms-extensions' to enable support for 
__declspec attributes}}
+
+struct S {
+  __declspec(property(get=Getter, put=Setter)) int X; // 
expected-error{{'__declspec' attributes are not enabled; use '-fdeclspec' or 
'-fms-extensions' to enable support for __declspec attributes}}
+  int Y;
+};
Index: lib/Parse/ParseDecl.cpp
===
--- lib/Parse/ParseDecl.cpp
+++ lib/Parse/ParseDecl.cpp
@@ -2966,6 +2966,31 @@
   if (DS.hasTypeSpecifier())
 goto DoneWithDeclSpec;
 
+  // If the token is an identifier named "__declspec" and Microsoft
+  // extensions are not enabled, it is likely that there will be cascading
+  // parse errors if this really is a __declspec attribute. Attempt to
+  // recognize that scenario and recover gracefully.
+  if (!getLangOpts().MicrosoftExt && Tok.is(tok::identifier) &&
+  Tok.getIdentifierInfo()->getName().equals("__declspec")) {
+// The next token should be an open paren. If it is, eat the entire
+// attribute declaration and continue.
+if (NextToken().is(tok::l_paren)) {
+  // Consume the __declspec identifier.
+  SourceLocation Loc = ConsumeToken();
+
+  // Eat the parens and everything between them.
+  BalancedDelimiterTracker T(*this, tok::l_paren);
+  if (T.consumeOpen()) {
+assert(false && "Not a left paren?");
+return;
+  }
+  T.skipToEnd();
+
+  Diag(Loc, diag::err_ms_attributes_not_enabled);
+  continue;
+}
+  }
+
   // In C++, check to see if this is a scope specifier like foo::bar::, if
   // so handle it as such.  This is important for ctor parsing.
   if (getLangOpts().CPlusPlus) {
Index: include/clang/Basic/DiagnosticParseKinds.td
===
--- include/clang/Basic/DiagnosticParseKinds.td
+++ include/clang/Basic/DiagnosticParseKinds.td
@@ -176,6 +176,9 @@
 def warn_attribute_no_decl : Warning<
   "attribute %0 ignored, because it is not attached to a declaration">, 
   InGroup;
+def err_ms_attributes_not_enabled : Error<
+  "'__declspec' attributes are not enabled; use '-fdeclspec' or "
+  "'-fms-extensions' to enable support for __declspec attributes">;
 def err_expected_method_body : Error<"expected method body">;
 def err_declspec_after_virtspec : Error<
   "'%0' qualifier may not appear after the virtual specifier '%1'">;


Index: test/Parser/declspec-supported.c
===
--- test/Parser/declspec-supported.c
+++ test/Parser/declspec-supported.c
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -triple i386-pc-unknown -fsyntax-only -fms-extensions -verify