diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -976,6 +976,8 @@ def warn_pragma_invalid_argument : Warning< "unexpected argument '%0' to '#pragma %1'%select{|; expected %3}2">, InGroup; +def err_pragma_misplaced_in_decl : Error<"this pragma cannot appear in %0 declaration">; + // '#pragma clang section' related errors def err_pragma_expected_clang_section_name : Error< "expected one of [bss|data|rodata|text] section kind in '#pragma %0'">; diff --git a/clang/include/clang/Basic/TokenKinds.h b/clang/include/clang/Basic/TokenKinds.h --- a/clang/include/clang/Basic/TokenKinds.h +++ b/clang/include/clang/Basic/TokenKinds.h @@ -98,6 +98,9 @@ return false; } +/// Return true if this is an annotation token representing a pragma. +bool isPragmaAnnotation(TokenKind K); + } // end namespace tok } // end namespace clang diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -972,7 +972,7 @@ }; /// Consume any extra semi-colons until the end of the line. - void ConsumeExtraSemi(ExtraSemiKind Kind, unsigned TST = TST_unspecified); + void ConsumeExtraSemi(ExtraSemiKind Kind, DeclSpec::TST T = TST_unspecified); /// Return false if the next token is an identifier. An 'expected identifier' /// error is emitted otherwise. @@ -2160,7 +2160,7 @@ const ParsedTemplateInfo &TemplateInfo, AccessSpecifier AS, DeclSpecContext DSC); void ParseEnumBody(SourceLocation StartLoc, Decl *TagDecl); - void ParseStructUnionBody(SourceLocation StartLoc, unsigned TagType, + void ParseStructUnionBody(SourceLocation StartLoc, DeclSpec::TST TagType, Decl *TagDecl); void ParseStructDeclaration( diff --git a/clang/lib/Basic/TokenKinds.cpp b/clang/lib/Basic/TokenKinds.cpp --- a/clang/lib/Basic/TokenKinds.cpp +++ b/clang/lib/Basic/TokenKinds.cpp @@ -12,6 +12,7 @@ #include "clang/Basic/TokenKinds.h" #include "llvm/Support/ErrorHandling.h" +#include using namespace clang; static const char * const TokNames[] = { @@ -45,3 +46,15 @@ } return nullptr; } + +bool tok::isPragmaAnnotation(TokenKind Kind) { + switch (Kind) { +#define ANNOTATION(X) \ + case annot_##X: \ + return std::strncmp(#X, "pragma_", sizeof("pragma_") - 1) == 0; +#include "clang/Basic/TokenKinds.def" + default: + break; + } + return false; +} diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -4080,7 +4080,7 @@ /// [OBC] '@' 'defs' '(' class-name ')' /// void Parser::ParseStructUnionBody(SourceLocation RecordLoc, - unsigned TagType, Decl *TagDecl) { + DeclSpec::TST TagType, Decl *TagDecl) { PrettyDeclStackTraceEntry CrashInfo(Actions.Context, TagDecl, RecordLoc, "parsing struct/union body"); assert(!getLangOpts().CPlusPlus && "C++ declarations not supported"); @@ -4130,6 +4130,14 @@ continue; } + if (tok::isPragmaAnnotation(Tok.getKind())) { + Diag(Tok.getLocation(), diag::err_pragma_misplaced_in_decl) + << DeclSpec::getSpecifierName( + TagType, Actions.getASTContext().getPrintingPolicy()); + ConsumeAnnotationToken(); + continue; + } + if (!Tok.is(tok::at)) { auto CFieldCallback = [&](ParsingFieldDeclarator &FD) { // Install the declarator into the current TagDecl. diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -3134,6 +3134,13 @@ TagDecl); default: + if (tok::isPragmaAnnotation(Tok.getKind())) { + Diag(Tok.getLocation(), diag::err_pragma_misplaced_in_decl) + << DeclSpec::getSpecifierName(TagType, + Actions.getASTContext().getPrintingPolicy()); + ConsumeAnnotationToken(); + return nullptr; + } return ParseCXXClassMemberDeclaration(AS, AccessAttrs); } } @@ -4337,7 +4344,7 @@ while (Tok.isNot(tok::r_brace) && !isEofOrEom()) { // __if_exists, __if_not_exists can nest. if (Tok.isOneOf(tok::kw___if_exists, tok::kw___if_not_exists)) { - ParseMicrosoftIfExistsClassDeclaration((DeclSpec::TST)TagType, + ParseMicrosoftIfExistsClassDeclaration(TagType, AccessAttrs, CurAS); continue; } diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -174,7 +174,7 @@ return ExpectAndConsume(tok::semi, DiagID); } -void Parser::ConsumeExtraSemi(ExtraSemiKind Kind, unsigned TST) { +void Parser::ConsumeExtraSemi(ExtraSemiKind Kind, DeclSpec::TST TST) { if (!Tok.is(tok::semi)) return; bool HadMultipleSemis = false; @@ -202,7 +202,7 @@ if (Kind != AfterMemberFunctionDefinition || HadMultipleSemis) Diag(StartLoc, diag::ext_extra_semi) - << Kind << DeclSpec::getSpecifierName((DeclSpec::TST)TST, + << Kind << DeclSpec::getSpecifierName(TST, Actions.getASTContext().getPrintingPolicy()) << FixItHint::CreateRemoval(SourceRange(StartLoc, EndLoc)); else diff --git a/clang/test/Parser/pragma-attribute-context.cpp b/clang/test/Parser/pragma-attribute-context.cpp --- a/clang/test/Parser/pragma-attribute-context.cpp +++ b/clang/test/Parser/pragma-attribute-context.cpp @@ -31,8 +31,7 @@ struct InStruct { // FIXME: This asserts in Objective-C++! - // FIXME: This is a horrible diagnostic! #ifndef __OBJC__ - BEGIN_PRAGMA // expected-error {{expected member name or ';' after declaration specifiers}} + BEGIN_PRAGMA // expected-error {{this pragma cannot appear in struct declaration}} #endif }; diff --git a/clang/test/Parser/pragma-fp-contract.c b/clang/test/Parser/pragma-fp-contract.c --- a/clang/test/Parser/pragma-fp-contract.c +++ b/clang/test/Parser/pragma-fp-contract.c @@ -10,3 +10,16 @@ #pragma STDC FP_CONTRACT OFF #pragma STDC FP_CONTRACT ON } + +struct S1 { +// expected-error@+1 {{this pragma cannot appear in struct declaration}} +#pragma STDC FP_CONTRACT ON + float f1; +}; + +union U1 { + float f1; + float f2; +// expected-error@+1 {{this pragma cannot appear in union declaration}} +#pragma STDC FP_CONTRACT ON +}; diff --git a/clang/test/Parser/pragma-fp-contract.cpp b/clang/test/Parser/pragma-fp-contract.cpp new file mode 100644 --- /dev/null +++ b/clang/test/Parser/pragma-fp-contract.cpp @@ -0,0 +1,32 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +void f1(void) { + int x = 0; +/* expected-error@+1 {{'#pragma fp_contract' can only appear at file scope or at the start of a compound statement}} */ +#pragma STDC FP_CONTRACT ON +} + +void f2(void) { + #pragma STDC FP_CONTRACT OFF + #pragma STDC FP_CONTRACT ON +} + +struct S1 { +// expected-error@+1 {{this pragma cannot appear in struct declaration}} +#pragma STDC FP_CONTRACT ON + float f1; +}; + +union U1 { + float f1; + float f2; +// expected-error@+1 {{this pragma cannot appear in union declaration}} +#pragma STDC FP_CONTRACT ON +}; + +class C1 { + float f1; +// expected-error@+1 {{this pragma cannot appear in class declaration}} +#pragma STDC FP_CONTRACT ON + float f2; +};