diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 3556ea437fb5..fef34bdd9682 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -1757,53 +1757,53 @@ def MSVtorDisp : InheritableAttr { let Documentation = [Undocumented]; } -def Unaligned : IgnoredAttr { - let Spellings = [Keyword<"__unaligned">]; -} - -def LoopHint : Attr { - /// vectorize: vectorizes loop operations if 'value != 0'. - /// vectorize_width: vectorize loop operations with width 'value'. - /// interleave: interleave multiple loop iterations if 'value != 0'. - /// interleave_count: interleaves 'value' loop interations. - - /// FIXME: Add Pragma spelling to tablegen and - /// use it here. - let Spellings = [Keyword<"loop">]; - - /// State of the loop optimization specified by the spelling. - let Args = [EnumArgument<"Option", "OptionType", - ["vectorize", "vectorize_width", "interleave", "interleave_count"], - ["Vectorize", "VectorizeWidth", "Interleave", "InterleaveCount"]>, - DefaultIntArgument<"Value", 1>]; - - let AdditionalMembers = [{ - static StringRef getOptionName(int Option) { - switch(Option) { - case Vectorize: return "vectorize"; - case VectorizeWidth: return "vectorize_width"; - case Interleave: return "interleave"; - case InterleaveCount: return "interleave_count"; - } - llvm_unreachable("Unhandled LoopHint option."); - } - - static StringRef getValueName(int Value) { - if (Value) - return "enable"; - return "disable"; - } - - // FIXME: Modify pretty printer to print this pragma. - void print(raw_ostream &OS, const PrintingPolicy &Policy) const { - OS << "#pragma clang loop " << getOptionName(option) << "("; - if (option == VectorizeWidth || option == InterleaveCount) - OS << value; - else - OS << getValueName(value); - OS << ")\n"; - } - }]; - - let Documentation = [Undocumented]; -} +def Unaligned : IgnoredAttr { + let Spellings = [Keyword<"__unaligned">]; +} + +def LoopHint : Attr { + /// vectorize: vectorizes loop operations if 'value != 0'. + /// vectorize_width: vectorize loop operations with width 'value'. + /// interleave: interleave multiple loop iterations if 'value != 0'. + /// interleave_count: interleaves 'value' loop interations. + + /// FIXME: Add Pragma spelling to tablegen and + /// use it here. + let Spellings = [Keyword<"loop">]; + + /// State of the loop optimization specified by the spelling. + let Args = [EnumArgument<"Option", "OptionType", + ["vectorize", "vectorize_width", "interleave", "interleave_count"], + ["Vectorize", "VectorizeWidth", "Interleave", "InterleaveCount"]>, + DefaultIntArgument<"Value", 1>]; + + let AdditionalMembers = [{ + static StringRef getOptionName(int Option) { + switch(Option) { + case Vectorize: return "vectorize"; + case VectorizeWidth: return "vectorize_width"; + case Interleave: return "interleave"; + case InterleaveCount: return "interleave_count"; + } + llvm_unreachable("Unhandled LoopHint option."); + } + + static StringRef getValueName(int Value) { + if (Value) + return "enable"; + return "disable"; + } + + // FIXME: Modify pretty printer to print this pragma. + void print(raw_ostream &OS, const PrintingPolicy &Policy) const { + OS << "#pragma clang loop " << getOptionName(option) << "("; + if (option == VectorizeWidth || option == InterleaveCount) + OS << value; + else + OS << getValueName(value); + OS << ")\n"; + } + }]; + + let Documentation = [Undocumented]; +} diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index 2ab5021fdc46..50c5985675ec 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -889,16 +889,16 @@ def err_omp_unexpected_directive : Error< def err_omp_expected_punc : Error< "expected ',' or ')' in '%0' clause">; def err_omp_unexpected_clause : Error< - "unexpected OpenMP clause '%0' in directive '#pragma omp %1'">; -def err_omp_more_one_clause : Error< - "directive '#pragma omp %0' cannot contain more than one '%1' clause">; - -// Pragma loop support. -def err_pragma_loop_invalid_option : Error< - "%select{invalid|missing}0 option%select{ %1|}0; expected vectorize, vectorize_width, interleave, or interleave_count">; -} // end of Parse Issue category. - -let CategoryName = "Modules Issue" in { + "unexpected OpenMP clause '%0' in directive '#pragma omp %1'">; +def err_omp_more_one_clause : Error< + "directive '#pragma omp %0' cannot contain more than one '%1' clause">; + +// Pragma loop support. +def err_pragma_loop_invalid_option : Error< + "%select{invalid|missing}0 option%select{ %1|}0; expected vectorize, vectorize_width, interleave, or interleave_count">; +} // end of Parse Issue category. + +let CategoryName = "Modules Issue" in { def err_module_expected_ident : Error< "expected a module name after module import">; def err_module_expected_semi : Error< diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index f49ff18b86f0..34e774671ed2 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -539,21 +539,21 @@ def err_pragma_push_visibility_mismatch : Error< def note_surrounding_namespace_ends_here : Note< "surrounding namespace with visibility attribute ends here">; def err_pragma_pop_visibility_mismatch : Error< - "#pragma visibility pop with no matching #pragma visibility push">; -def note_surrounding_namespace_starts_here : Note< - "surrounding namespace with visibility attribute starts here">; -def err_pragma_loop_invalid_value : Error< - "%select{invalid|missing}0 value%select{ %1|}0; expected a positive integer value">; -def err_pragma_loop_invalid_keyword : Error< - "%select{invalid|missing}0 keyword%select{ %1|}0; expected 'enable' or 'disable'">; -def err_pragma_loop_compatibility : Error< - "%select{incompatible|duplicate}0 directives '%1(%2)' and '%3(%4)'">; -def err_pragma_loop_precedes_nonloop : Error< - "expected a for, while, or do-while loop to follow the '#pragma clang loop' " - "directive">; - -/// Objective-C parser diagnostics -def err_duplicate_class_def : Error< + "#pragma visibility pop with no matching #pragma visibility push">; +def note_surrounding_namespace_starts_here : Note< + "surrounding namespace with visibility attribute starts here">; +def err_pragma_loop_invalid_value : Error< + "%select{invalid|missing}0 value%select{ %1|}0; expected a positive integer value">; +def err_pragma_loop_invalid_keyword : Error< + "%select{invalid|missing}0 keyword%select{ %1|}0; expected 'enable' or 'disable'">; +def err_pragma_loop_compatibility : Error< + "%select{incompatible|duplicate}0 directives '%1(%2)' and '%3(%4)'">; +def err_pragma_loop_precedes_nonloop : Error< + "expected a for, while, or do-while loop to follow the '#pragma clang loop' " + "directive">; + +/// Objective-C parser diagnostics +def err_duplicate_class_def : Error< "duplicate interface definition for class %0">; def err_undef_superclass : Error< "cannot find interface declaration for %0, superclass of %1">; diff --git a/clang/lib/Parse/ParsePragma.cpp b/clang/lib/Parse/ParsePragma.cpp index 427a44d8901a..4ce17e7b72eb 100644 --- a/clang/lib/Parse/ParsePragma.cpp +++ b/clang/lib/Parse/ParsePragma.cpp @@ -12,13 +12,13 @@ //===----------------------------------------------------------------------===// #include "RAIIObjectsForParser.h" -#include "clang/Lex/Preprocessor.h" -#include "clang/Parse/ParseDiagnostic.h" -#include "clang/Parse/Parser.h" -#include "clang/Sema/LoopHint.h" -#include "clang/Sema/Scope.h" -#include "llvm/ADT/StringSwitch.h" -using namespace clang; +#include "clang/Lex/Preprocessor.h" +#include "clang/Parse/ParseDiagnostic.h" +#include "clang/Parse/Parser.h" +#include "clang/Sema/LoopHint.h" +#include "clang/Sema/Scope.h" +#include "llvm/ADT/StringSwitch.h" +using namespace clang; namespace { @@ -139,18 +139,18 @@ struct PragmaOptimizeHandler : public PragmaHandler { void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, Token &FirstToken) override; private: - Sema &Actions; -}; - -struct PragmaLoopHintHandler : public PragmaHandler { - PragmaLoopHintHandler() : PragmaHandler("loop") {} - void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, - Token &FirstToken) override; -}; - -} // end namespace - -void Parser::initializePragmaHandlers() { + Sema &Actions; +}; + +struct PragmaLoopHintHandler : public PragmaHandler { + PragmaLoopHintHandler() : PragmaHandler("loop") {} + void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, + Token &FirstToken) override; +}; + +} // end namespace + +void Parser::initializePragmaHandlers() { AlignHandler.reset(new PragmaAlignHandler()); PP.AddPragmaHandler(AlignHandler.get()); @@ -212,15 +212,15 @@ void Parser::initializePragmaHandlers() { MSSection.reset(new PragmaMSPragma("section")); PP.AddPragmaHandler(MSSection.get()); } - - OptimizeHandler.reset(new PragmaOptimizeHandler(Actions)); - PP.AddPragmaHandler("clang", OptimizeHandler.get()); - - LoopHintHandler.reset(new PragmaLoopHintHandler()); - PP.AddPragmaHandler("clang", LoopHintHandler.get()); -} - -void Parser::resetPragmaHandlers() { + + OptimizeHandler.reset(new PragmaOptimizeHandler(Actions)); + PP.AddPragmaHandler("clang", OptimizeHandler.get()); + + LoopHintHandler.reset(new PragmaLoopHintHandler()); + PP.AddPragmaHandler("clang", LoopHintHandler.get()); +} + +void Parser::resetPragmaHandlers() { // Remove the pragma handlers we installed. PP.RemovePragmaHandler(AlignHandler.get()); AlignHandler.reset(); @@ -272,15 +272,15 @@ void Parser::resetPragmaHandlers() { PP.RemovePragmaHandler("STDC", FPContractHandler.get()); FPContractHandler.reset(); - - PP.RemovePragmaHandler("clang", OptimizeHandler.get()); - OptimizeHandler.reset(); - - PP.RemovePragmaHandler("clang", LoopHintHandler.get()); - LoopHintHandler.reset(); -} - -/// \brief Handle the annotation token produced for #pragma unused(...) + + PP.RemovePragmaHandler("clang", OptimizeHandler.get()); + OptimizeHandler.reset(); + + PP.RemovePragmaHandler("clang", LoopHintHandler.get()); + LoopHintHandler.reset(); +} + +/// \brief Handle the annotation token produced for #pragma unused(...) /// /// Each annot_pragma_unused is followed by the argument token so e.g. /// "#pragma unused(x,y)" becomes: @@ -596,46 +596,46 @@ unsigned Parser::HandlePragmaMSSegment(llvm::StringRef PragmaName, unsigned Parser::HandlePragmaMSInitSeg(llvm::StringRef PragmaName, SourceLocation PragmaLocation) { return PP.getDiagnostics().getCustomDiagID( - DiagnosticsEngine::Error, "'#pragma %0' not implemented."); -} - -struct PragmaLoopHintInfo { - Token Loop; - Token Value; - Token Option; -}; - -LoopHint Parser::HandlePragmaLoopHint() { - assert(Tok.is(tok::annot_pragma_loop_hint)); - PragmaLoopHintInfo *Info = - static_cast(Tok.getAnnotationValue()); - - LoopHint Hint; - Hint.LoopLoc = - IdentifierLoc::create(Actions.Context, Info->Loop.getLocation(), - Info->Loop.getIdentifierInfo()); - Hint.OptionLoc = - IdentifierLoc::create(Actions.Context, Info->Option.getLocation(), - Info->Option.getIdentifierInfo()); - Hint.ValueLoc = - IdentifierLoc::create(Actions.Context, Info->Value.getLocation(), - Info->Value.getIdentifierInfo()); - Hint.Range = - SourceRange(Info->Option.getLocation(), Info->Value.getLocation()); - - // FIXME: We should support template parameters for the loop hint value. - // See bug report #19610 - if (Info->Value.is(tok::numeric_constant)) - Hint.ValueExpr = Actions.ActOnNumericConstant(Info->Value).get(); - else - Hint.ValueExpr = nullptr; - - return Hint; -} - -// #pragma GCC visibility comes in two variants: -// 'push' '(' [visibility] ')' -// 'pop' + DiagnosticsEngine::Error, "'#pragma %0' not implemented."); +} + +struct PragmaLoopHintInfo { + Token Loop; + Token Value; + Token Option; +}; + +LoopHint Parser::HandlePragmaLoopHint() { + assert(Tok.is(tok::annot_pragma_loop_hint)); + PragmaLoopHintInfo *Info = + static_cast(Tok.getAnnotationValue()); + + LoopHint Hint; + Hint.LoopLoc = + IdentifierLoc::create(Actions.Context, Info->Loop.getLocation(), + Info->Loop.getIdentifierInfo()); + Hint.OptionLoc = + IdentifierLoc::create(Actions.Context, Info->Option.getLocation(), + Info->Option.getIdentifierInfo()); + Hint.ValueLoc = + IdentifierLoc::create(Actions.Context, Info->Value.getLocation(), + Info->Value.getIdentifierInfo()); + Hint.Range = + SourceRange(Info->Option.getLocation(), Info->Value.getLocation()); + + // FIXME: We should support template parameters for the loop hint value. + // See bug report #19610 + if (Info->Value.is(tok::numeric_constant)) + Hint.ValueExpr = Actions.ActOnNumericConstant(Info->Value).get(); + else + Hint.ValueExpr = nullptr; + + return Hint; +} + +// #pragma GCC visibility comes in two variants: +// 'push' '(' [visibility] ')' +// 'pop' void PragmaGCCVisibilityHandler::HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, Token &VisTok) { @@ -1628,113 +1628,113 @@ void PragmaOptimizeHandler::HandlePragma(Preprocessor &PP, << PP.getSpelling(Tok); return; } - - Actions.ActOnPragmaOptimize(IsOn, FirstToken.getLocation()); -} - -/// \brief Handle the \#pragma clang loop directive. -/// #pragma clang 'loop' loop-hints -/// -/// loop-hints: -/// loop-hint loop-hints[opt] -/// -/// loop-hint: -/// 'vectorize' '(' loop-hint-keyword ')' -/// 'interleave' '(' loop-hint-keyword ')' -/// 'vectorize_width' '(' loop-hint-value ')' -/// 'interleave_count' '(' loop-hint-value ')' -/// -/// loop-hint-keyword: -/// 'enable' -/// 'disable' -/// -/// loop-hint-value: -/// constant-expression -/// -/// Specifying vectorize(enable) or vectorize_width(_value_) instructs llvm to -/// try vectorizing the instructions of the loop it precedes. Specifying -/// interleave(enable) or interleave_count(_value_) instructs llvm to try -/// interleaving multiple iterations of the loop it precedes. The width of the -/// vector instructions is specified by vectorize_width() and the number of -/// interleaved loop iterations is specified by interleave_count(). Specifying a -/// value of 1 effectively disables vectorization/interleaving, even if it is -/// possible and profitable, and 0 is invalid. The loop vectorizer currently -/// only works on inner loops. -/// -void PragmaLoopHintHandler::HandlePragma(Preprocessor &PP, - PragmaIntroducerKind Introducer, - Token &Tok) { - Token Loop = Tok; - SmallVector TokenList; - - // Lex the optimization option and verify it is an identifier. - PP.Lex(Tok); - if (Tok.isNot(tok::identifier)) { - PP.Diag(Tok.getLocation(), diag::err_pragma_loop_invalid_option) - << /*MissingOption=*/true << ""; - return; - } - - while (Tok.is(tok::identifier)) { - Token Option = Tok; - IdentifierInfo *OptionInfo = Tok.getIdentifierInfo(); - - if (!OptionInfo->isStr("vectorize") && !OptionInfo->isStr("interleave") && - !OptionInfo->isStr("vectorize_width") && - !OptionInfo->isStr("interleave_count")) { - PP.Diag(Tok.getLocation(), diag::err_pragma_loop_invalid_option) - << /*MissingOption=*/false << OptionInfo; - return; - } - - // Read '(' - PP.Lex(Tok); - if (Tok.isNot(tok::l_paren)) { - PP.Diag(Tok.getLocation(), diag::err_expected) << tok::l_paren; - return; - } - - // FIXME: All tokens between '(' and ')' should be stored and parsed as a - // constant expression. - PP.Lex(Tok); - Token Value; - if (Tok.is(tok::identifier) || Tok.is(tok::numeric_constant)) - Value = Tok; - - // Read ')' - PP.Lex(Tok); - if (Tok.isNot(tok::r_paren)) { - PP.Diag(Tok.getLocation(), diag::err_expected) << tok::r_paren; - return; - } - - // Get next optimization option. - PP.Lex(Tok); - - auto *Info = new (PP.getPreprocessorAllocator()) PragmaLoopHintInfo; - Info->Loop = Loop; - Info->Option = Option; - Info->Value = Value; - - // Generate the vectorization hint token. - Token LoopHintTok; - LoopHintTok.startToken(); - LoopHintTok.setKind(tok::annot_pragma_loop_hint); - LoopHintTok.setLocation(Loop.getLocation()); - LoopHintTok.setAnnotationValue(static_cast(Info)); - TokenList.push_back(LoopHintTok); - } - - if (Tok.isNot(tok::eod)) { - PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) - << "clang loop"; - return; - } - - Token *TokenArray = new Token[TokenList.size()]; - std::copy(TokenList.begin(), TokenList.end(), TokenArray); - - PP.EnterTokenStream(TokenArray, TokenList.size(), - /*DisableMacroExpansion=*/false, - /*OwnsTokens=*/true); -} + + Actions.ActOnPragmaOptimize(IsOn, FirstToken.getLocation()); +} + +/// \brief Handle the \#pragma clang loop directive. +/// #pragma clang 'loop' loop-hints +/// +/// loop-hints: +/// loop-hint loop-hints[opt] +/// +/// loop-hint: +/// 'vectorize' '(' loop-hint-keyword ')' +/// 'interleave' '(' loop-hint-keyword ')' +/// 'vectorize_width' '(' loop-hint-value ')' +/// 'interleave_count' '(' loop-hint-value ')' +/// +/// loop-hint-keyword: +/// 'enable' +/// 'disable' +/// +/// loop-hint-value: +/// constant-expression +/// +/// Specifying vectorize(enable) or vectorize_width(_value_) instructs llvm to +/// try vectorizing the instructions of the loop it precedes. Specifying +/// interleave(enable) or interleave_count(_value_) instructs llvm to try +/// interleaving multiple iterations of the loop it precedes. The width of the +/// vector instructions is specified by vectorize_width() and the number of +/// interleaved loop iterations is specified by interleave_count(). Specifying a +/// value of 1 effectively disables vectorization/interleaving, even if it is +/// possible and profitable, and 0 is invalid. The loop vectorizer currently +/// only works on inner loops. +/// +void PragmaLoopHintHandler::HandlePragma(Preprocessor &PP, + PragmaIntroducerKind Introducer, + Token &Tok) { + Token Loop = Tok; + SmallVector TokenList; + + // Lex the optimization option and verify it is an identifier. + PP.Lex(Tok); + if (Tok.isNot(tok::identifier)) { + PP.Diag(Tok.getLocation(), diag::err_pragma_loop_invalid_option) + << /*MissingOption=*/true << ""; + return; + } + + while (Tok.is(tok::identifier)) { + Token Option = Tok; + IdentifierInfo *OptionInfo = Tok.getIdentifierInfo(); + + if (!OptionInfo->isStr("vectorize") && !OptionInfo->isStr("interleave") && + !OptionInfo->isStr("vectorize_width") && + !OptionInfo->isStr("interleave_count")) { + PP.Diag(Tok.getLocation(), diag::err_pragma_loop_invalid_option) + << /*MissingOption=*/false << OptionInfo; + return; + } + + // Read '(' + PP.Lex(Tok); + if (Tok.isNot(tok::l_paren)) { + PP.Diag(Tok.getLocation(), diag::err_expected) << tok::l_paren; + return; + } + + // FIXME: All tokens between '(' and ')' should be stored and parsed as a + // constant expression. + PP.Lex(Tok); + Token Value; + if (Tok.is(tok::identifier) || Tok.is(tok::numeric_constant)) + Value = Tok; + + // Read ')' + PP.Lex(Tok); + if (Tok.isNot(tok::r_paren)) { + PP.Diag(Tok.getLocation(), diag::err_expected) << tok::r_paren; + return; + } + + // Get next optimization option. + PP.Lex(Tok); + + auto *Info = new (PP.getPreprocessorAllocator()) PragmaLoopHintInfo; + Info->Loop = Loop; + Info->Option = Option; + Info->Value = Value; + + // Generate the vectorization hint token. + Token LoopHintTok; + LoopHintTok.startToken(); + LoopHintTok.setKind(tok::annot_pragma_loop_hint); + LoopHintTok.setLocation(Loop.getLocation()); + LoopHintTok.setAnnotationValue(static_cast(Info)); + TokenList.push_back(LoopHintTok); + } + + if (Tok.isNot(tok::eod)) { + PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) + << "clang loop"; + return; + } + + Token *TokenArray = new Token[TokenList.size()]; + std::copy(TokenList.begin(), TokenList.end(), TokenArray); + + PP.EnterTokenStream(TokenArray, TokenList.size(), + /*DisableMacroExpansion=*/false, + /*OwnsTokens=*/true); +} diff --git a/clang/lib/Sema/SemaStmtAttr.cpp b/clang/lib/Sema/SemaStmtAttr.cpp index 5b1766a0b26f..1ec42ef0af7f 100644 --- a/clang/lib/Sema/SemaStmtAttr.cpp +++ b/clang/lib/Sema/SemaStmtAttr.cpp @@ -13,13 +13,13 @@ #include "clang/Sema/SemaInternal.h" #include "clang/AST/ASTContext.h" -#include "clang/Basic/SourceManager.h" -#include "clang/Sema/DelayedDiagnostic.h" -#include "clang/Sema/Lookup.h" -#include "clang/Sema/LoopHint.h" -#include "clang/Sema/ScopeInfo.h" -#include "llvm/ADT/StringExtras.h" - +#include "clang/Basic/SourceManager.h" +#include "clang/Sema/DelayedDiagnostic.h" +#include "clang/Sema/Lookup.h" +#include "clang/Sema/LoopHint.h" +#include "clang/Sema/ScopeInfo.h" +#include "llvm/ADT/StringExtras.h" + using namespace clang; using namespace sema; @@ -40,176 +40,176 @@ static Attr *handleFallThroughAttr(Sema &S, Stmt *St, const AttributeList &A, return nullptr; } return ::new (S.Context) FallThroughAttr(A.getRange(), S.Context, - A.getAttributeSpellingListIndex()); -} - -static Attr *handleLoopHintAttr(Sema &S, Stmt *St, const AttributeList &A, - SourceRange) { - if (St->getStmtClass() != Stmt::DoStmtClass && - St->getStmtClass() != Stmt::ForStmtClass && - St->getStmtClass() != Stmt::CXXForRangeStmtClass && - St->getStmtClass() != Stmt::WhileStmtClass) { - S.Diag(St->getLocStart(), diag::err_pragma_loop_precedes_nonloop); - return nullptr; - } - - IdentifierLoc *OptionLoc = A.getArgAsIdent(0); - IdentifierInfo *OptionInfo = OptionLoc->Ident; - IdentifierLoc *ValueLoc = A.getArgAsIdent(1); - IdentifierInfo *ValueInfo = ValueLoc->Ident; - Expr *ValueExpr = A.getArgAsExpr(2); - - assert(OptionInfo && "Attribute must have valid option info."); - - LoopHintAttr::OptionType Option = - llvm::StringSwitch(OptionInfo->getNameStart()) - .Case("vectorize", LoopHintAttr::Vectorize) - .Case("vectorize_width", LoopHintAttr::VectorizeWidth) - .Case("interleave", LoopHintAttr::Interleave) - .Case("interleave_count", LoopHintAttr::InterleaveCount) - .Default(LoopHintAttr::Vectorize); - - int ValueInt; - if (Option == LoopHintAttr::Vectorize || Option == LoopHintAttr::Interleave) { - if (!ValueInfo) { - S.Diag(ValueLoc->Loc, diag::err_pragma_loop_invalid_keyword) - << /*MissingKeyword=*/true << ""; - return nullptr; - } - - if (ValueInfo->isStr("disable")) - ValueInt = 0; - else if (ValueInfo->isStr("enable")) - ValueInt = 1; - else { - S.Diag(ValueLoc->Loc, diag::err_pragma_loop_invalid_keyword) - << /*MissingKeyword=*/false << ValueInfo; - return nullptr; - } - } else if (Option == LoopHintAttr::VectorizeWidth || - Option == LoopHintAttr::InterleaveCount) { - // FIXME: We should support template parameters for the loop hint value. - // See bug report #19610. - llvm::APSInt ValueAPS; - if (!ValueExpr || !ValueExpr->isIntegerConstantExpr(ValueAPS, S.Context)) { - S.Diag(ValueLoc->Loc, diag::err_pragma_loop_invalid_value) - << /*MissingValue=*/true << ""; - return nullptr; - } - - if ((ValueInt = ValueAPS.getSExtValue()) < 1) { - S.Diag(ValueLoc->Loc, diag::err_pragma_loop_invalid_value) - << /*MissingValue=*/false << ValueInt; - return nullptr; - } - } else - llvm_unreachable("Unknown loop hint option"); - - return LoopHintAttr::CreateImplicit(S.Context, Option, ValueInt, - A.getRange()); -} - -static void -CheckForIncompatibleAttributes(Sema &S, SmallVectorImpl &Attrs) { - int PrevOptionValue[4] = {-1, -1, -1, -1}; - int OptionId[4] = {LoopHintAttr::Vectorize, LoopHintAttr::VectorizeWidth, - LoopHintAttr::Interleave, LoopHintAttr::InterleaveCount}; - - for (const auto *I : Attrs) { - const LoopHintAttr *LH = dyn_cast(I); - - // Skip non loop hint attributes - if (!LH) - continue; - - int State, Value; - int Option = LH->getOption(); - int ValueInt = LH->getValue(); - - switch (Option) { - case LoopHintAttr::Vectorize: - case LoopHintAttr::VectorizeWidth: - State = 0; - Value = 1; - break; - case LoopHintAttr::Interleave: - case LoopHintAttr::InterleaveCount: - State = 2; - Value = 3; - break; - } - - SourceLocation ValueLoc = LH->getRange().getEnd(); - - // Compatibility testing is split into two cases. - // 1. if the current loop hint sets state (enable/disable) - check against - // previous state and value. - // 2. if the current loop hint sets a value - check against previous state - // and value. - - if (Option == State) { - if (PrevOptionValue[State] != -1) { - // Cannot specify state twice. - int PrevValue = PrevOptionValue[State]; - S.Diag(ValueLoc, diag::err_pragma_loop_compatibility) - << /*Duplicate=*/true << LoopHintAttr::getOptionName(Option) - << LoopHintAttr::getValueName(PrevValue) - << LoopHintAttr::getOptionName(Option) - << LoopHintAttr::getValueName(Value); - } - - if (PrevOptionValue[Value] != -1) { - // Compare state with previous width/count. - int PrevOption = OptionId[Value]; - int PrevValueInt = PrevOptionValue[Value]; - if ((ValueInt == 0 && PrevValueInt > 1) || - (ValueInt == 1 && PrevValueInt <= 1)) - S.Diag(ValueLoc, diag::err_pragma_loop_compatibility) - << /*Duplicate=*/false << LoopHintAttr::getOptionName(PrevOption) - << PrevValueInt << LoopHintAttr::getOptionName(Option) - << LoopHintAttr::getValueName(ValueInt); - } - } else { - if (PrevOptionValue[State] != -1) { - // Compare width/count value with previous state. - int PrevOption = OptionId[State]; - int PrevValueInt = PrevOptionValue[State]; - if ((ValueInt > 1 && PrevValueInt == 0) || - (ValueInt <= 1 && PrevValueInt == 1)) - S.Diag(ValueLoc, diag::err_pragma_loop_compatibility) - << /*Duplicate=*/false << LoopHintAttr::getOptionName(PrevOption) - << LoopHintAttr::getValueName(PrevValueInt) - << LoopHintAttr::getOptionName(Option) << ValueInt; - } - - if (PrevOptionValue[Value] != -1) { - // Cannot specify a width/count twice. - int PrevValueInt = PrevOptionValue[Value]; - S.Diag(ValueLoc, diag::err_pragma_loop_compatibility) - << /*Duplicate=*/true << LoopHintAttr::getOptionName(Option) - << PrevValueInt << LoopHintAttr::getOptionName(Option) << ValueInt; - } - } - - PrevOptionValue[Option] = ValueInt; - } -} - -static Attr *ProcessStmtAttribute(Sema &S, Stmt *St, const AttributeList &A, - SourceRange Range) { - switch (A.getKind()) { + A.getAttributeSpellingListIndex()); +} + +static Attr *handleLoopHintAttr(Sema &S, Stmt *St, const AttributeList &A, + SourceRange) { + if (St->getStmtClass() != Stmt::DoStmtClass && + St->getStmtClass() != Stmt::ForStmtClass && + St->getStmtClass() != Stmt::CXXForRangeStmtClass && + St->getStmtClass() != Stmt::WhileStmtClass) { + S.Diag(St->getLocStart(), diag::err_pragma_loop_precedes_nonloop); + return nullptr; + } + + IdentifierLoc *OptionLoc = A.getArgAsIdent(0); + IdentifierInfo *OptionInfo = OptionLoc->Ident; + IdentifierLoc *ValueLoc = A.getArgAsIdent(1); + IdentifierInfo *ValueInfo = ValueLoc->Ident; + Expr *ValueExpr = A.getArgAsExpr(2); + + assert(OptionInfo && "Attribute must have valid option info."); + + LoopHintAttr::OptionType Option = + llvm::StringSwitch(OptionInfo->getNameStart()) + .Case("vectorize", LoopHintAttr::Vectorize) + .Case("vectorize_width", LoopHintAttr::VectorizeWidth) + .Case("interleave", LoopHintAttr::Interleave) + .Case("interleave_count", LoopHintAttr::InterleaveCount) + .Default(LoopHintAttr::Vectorize); + + int ValueInt; + if (Option == LoopHintAttr::Vectorize || Option == LoopHintAttr::Interleave) { + if (!ValueInfo) { + S.Diag(ValueLoc->Loc, diag::err_pragma_loop_invalid_keyword) + << /*MissingKeyword=*/true << ""; + return nullptr; + } + + if (ValueInfo->isStr("disable")) + ValueInt = 0; + else if (ValueInfo->isStr("enable")) + ValueInt = 1; + else { + S.Diag(ValueLoc->Loc, diag::err_pragma_loop_invalid_keyword) + << /*MissingKeyword=*/false << ValueInfo; + return nullptr; + } + } else if (Option == LoopHintAttr::VectorizeWidth || + Option == LoopHintAttr::InterleaveCount) { + // FIXME: We should support template parameters for the loop hint value. + // See bug report #19610. + llvm::APSInt ValueAPS; + if (!ValueExpr || !ValueExpr->isIntegerConstantExpr(ValueAPS, S.Context)) { + S.Diag(ValueLoc->Loc, diag::err_pragma_loop_invalid_value) + << /*MissingValue=*/true << ""; + return nullptr; + } + + if ((ValueInt = ValueAPS.getSExtValue()) < 1) { + S.Diag(ValueLoc->Loc, diag::err_pragma_loop_invalid_value) + << /*MissingValue=*/false << ValueInt; + return nullptr; + } + } else + llvm_unreachable("Unknown loop hint option"); + + return LoopHintAttr::CreateImplicit(S.Context, Option, ValueInt, + A.getRange()); +} + +static void +CheckForIncompatibleAttributes(Sema &S, SmallVectorImpl &Attrs) { + int PrevOptionValue[4] = {-1, -1, -1, -1}; + int OptionId[4] = {LoopHintAttr::Vectorize, LoopHintAttr::VectorizeWidth, + LoopHintAttr::Interleave, LoopHintAttr::InterleaveCount}; + + for (const auto *I : Attrs) { + const LoopHintAttr *LH = dyn_cast(I); + + // Skip non loop hint attributes + if (!LH) + continue; + + int State, Value; + int Option = LH->getOption(); + int ValueInt = LH->getValue(); + + switch (Option) { + case LoopHintAttr::Vectorize: + case LoopHintAttr::VectorizeWidth: + State = 0; + Value = 1; + break; + case LoopHintAttr::Interleave: + case LoopHintAttr::InterleaveCount: + State = 2; + Value = 3; + break; + } + + SourceLocation ValueLoc = LH->getRange().getEnd(); + + // Compatibility testing is split into two cases. + // 1. if the current loop hint sets state (enable/disable) - check against + // previous state and value. + // 2. if the current loop hint sets a value - check against previous state + // and value. + + if (Option == State) { + if (PrevOptionValue[State] != -1) { + // Cannot specify state twice. + int PrevValue = PrevOptionValue[State]; + S.Diag(ValueLoc, diag::err_pragma_loop_compatibility) + << /*Duplicate=*/true << LoopHintAttr::getOptionName(Option) + << LoopHintAttr::getValueName(PrevValue) + << LoopHintAttr::getOptionName(Option) + << LoopHintAttr::getValueName(Value); + } + + if (PrevOptionValue[Value] != -1) { + // Compare state with previous width/count. + int PrevOption = OptionId[Value]; + int PrevValueInt = PrevOptionValue[Value]; + if ((ValueInt == 0 && PrevValueInt > 1) || + (ValueInt == 1 && PrevValueInt <= 1)) + S.Diag(ValueLoc, diag::err_pragma_loop_compatibility) + << /*Duplicate=*/false << LoopHintAttr::getOptionName(PrevOption) + << PrevValueInt << LoopHintAttr::getOptionName(Option) + << LoopHintAttr::getValueName(ValueInt); + } + } else { + if (PrevOptionValue[State] != -1) { + // Compare width/count value with previous state. + int PrevOption = OptionId[State]; + int PrevValueInt = PrevOptionValue[State]; + if ((ValueInt > 1 && PrevValueInt == 0) || + (ValueInt <= 1 && PrevValueInt == 1)) + S.Diag(ValueLoc, diag::err_pragma_loop_compatibility) + << /*Duplicate=*/false << LoopHintAttr::getOptionName(PrevOption) + << LoopHintAttr::getValueName(PrevValueInt) + << LoopHintAttr::getOptionName(Option) << ValueInt; + } + + if (PrevOptionValue[Value] != -1) { + // Cannot specify a width/count twice. + int PrevValueInt = PrevOptionValue[Value]; + S.Diag(ValueLoc, diag::err_pragma_loop_compatibility) + << /*Duplicate=*/true << LoopHintAttr::getOptionName(Option) + << PrevValueInt << LoopHintAttr::getOptionName(Option) << ValueInt; + } + } + + PrevOptionValue[Option] = ValueInt; + } +} + +static Attr *ProcessStmtAttribute(Sema &S, Stmt *St, const AttributeList &A, + SourceRange Range) { + switch (A.getKind()) { case AttributeList::UnknownAttribute: S.Diag(A.getLoc(), A.isDeclspecAttribute() ? diag::warn_unhandled_ms_attribute_ignored : diag::warn_unknown_attribute_ignored) << A.getName(); - return nullptr; - case AttributeList::AT_FallThrough: - return handleFallThroughAttr(S, St, A, Range); - case AttributeList::AT_LoopHint: - return handleLoopHintAttr(S, St, A, Range); - default: - // if we're here, then we parsed a known attribute, but didn't recognize - // it as a statement attribute => it is declaration attribute + return nullptr; + case AttributeList::AT_FallThrough: + return handleFallThroughAttr(S, St, A, Range); + case AttributeList::AT_LoopHint: + return handleLoopHintAttr(S, St, A, Range); + default: + // if we're here, then we parsed a known attribute, but didn't recognize + // it as a statement attribute => it is declaration attribute S.Diag(A.getRange().getBegin(), diag::err_attribute_invalid_on_stmt) << A.getName() << St->getLocStart(); return nullptr; @@ -221,13 +221,13 @@ StmtResult Sema::ProcessStmtAttributes(Stmt *S, AttributeList *AttrList, SmallVector Attrs; for (const AttributeList* l = AttrList; l; l = l->getNext()) { if (Attr *a = ProcessStmtAttribute(*this, S, *l, Range)) - Attrs.push_back(a); - } - - CheckForIncompatibleAttributes(*this, Attrs); - - if (Attrs.empty()) - return S; - + Attrs.push_back(a); + } + + CheckForIncompatibleAttributes(*this, Attrs); + + if (Attrs.empty()) + return S; + return ActOnAttributedStmt(Range.getBegin(), Attrs, S); } diff --git a/clang/test/CodeGenCXX/class-layout.cpp b/clang/test/CodeGenCXX/class-layout.cpp index c6aaf0f04608..d7d84a86abad 100644 --- a/clang/test/CodeGenCXX/class-layout.cpp +++ b/clang/test/CodeGenCXX/class-layout.cpp @@ -94,9 +94,9 @@ namespace Test7 { // Shouldn't crash. namespace Test8 { - struct A {}; - struct D { int a; }; - struct B : virtual D, A { }; - struct C : B, A { void f() {} }; - C c; + struct A {}; + struct D { int a; }; + struct B : virtual D, A { }; + struct C : B, A { void f() {} }; + C c; }