[PATCH] D29868: Recover more gracefully when __declspec is not supported as a keyword
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
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
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
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
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
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
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
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
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
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
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