Index: include/clang/Basic/Attr.td =================================================================== --- include/clang/Basic/Attr.td +++ include/clang/Basic/Attr.td @@ -210,6 +210,10 @@ string Namespace = namespace; int Version = version; } +class C2x : Spelling { + string Namespace = namespace; +} + class Keyword : Spelling; class Pragma : Spelling { string Namespace = namespace; @@ -958,7 +962,7 @@ def Deprecated : InheritableAttr { let Spellings = [GCC<"deprecated">, Declspec<"deprecated">, - CXX11<"","deprecated", 201309>]; + CXX11<"","deprecated", 201309>, C2x<"", "deprecated">]; let Args = [StringArgument<"Message", 1>, // An optional string argument that enables us to provide a // Fix-It. Index: include/clang/Basic/Attributes.h =================================================================== --- include/clang/Basic/Attributes.h +++ include/clang/Basic/Attributes.h @@ -26,6 +26,8 @@ Microsoft, // Is the identifier known as a C++-style attribute? CXX, + // Is the identifier known as a C-style attribute? + C2x, // Is the identifier known as a pragma attribute? Pragma }; Index: include/clang/Basic/DiagnosticGroups.td =================================================================== --- include/clang/Basic/DiagnosticGroups.td +++ include/clang/Basic/DiagnosticGroups.td @@ -173,6 +173,8 @@ def CXXPre2aCompatPedantic : DiagGroup<"c++98-c++11-c++14-c++17-compat-pedantic", [CXXPre2aCompat]>; +def C11Compat : DiagGroup<"c11-compat">; + def CXX98CompatBindToTemporaryCopy : DiagGroup<"c++98-compat-bind-to-temporary-copy">; def CXX98CompatLocalTypeTemplateArgs : Index: include/clang/Basic/DiagnosticParseKinds.td =================================================================== --- include/clang/Basic/DiagnosticParseKinds.td +++ include/clang/Basic/DiagnosticParseKinds.td @@ -567,6 +567,9 @@ def warn_cxx98_compat_attribute : Warning< "C++11 attribute syntax is incompatible with C++98">, InGroup, DefaultIgnore; +def warn_c11_compat_attribute : Warning< + "attribute syntax is incompatible with standards before C2x">, + InGroup, DefaultIgnore; def err_cxx11_attribute_forbids_arguments : Error< "attribute %0 cannot have an argument list">; def err_attribute_requires_arguments : Error< Index: include/clang/Basic/LangOptions.def =================================================================== --- include/clang/Basic/LangOptions.def +++ include/clang/Basic/LangOptions.def @@ -82,6 +82,7 @@ // FIXME: A lot of the BENIGN_ options should be COMPATIBLE_ instead. LANGOPT(C99 , 1, 0, "C99") LANGOPT(C11 , 1, 0, "C11") +LANGOPT(C2x , 1, 0, "C2x") LANGOPT(MSVCCompat , 1, 0, "Microsoft Visual C++ full compatibility mode") LANGOPT(MicrosoftExt , 1, 0, "Microsoft C++ extensions") LANGOPT(AsmBlocks , 1, 0, "Microsoft inline asm blocks") @@ -137,6 +138,9 @@ LANGOPT(CoroutinesTS , 1, 0, "C++ coroutines TS") LANGOPT(RelaxedTemplateTemplateArgs, 1, 0, "C++17 relaxed matching of template template arguments") +// TODO: If attributes are accepted by WG14, default on in C2x or remove flag. +LANGOPT(CAttributes , 1, 0, "'[[]]' attributes extension to C") + BENIGN_LANGOPT(ThreadsafeStatics , 1, 1, "thread-safe static initializers") LANGOPT(POSIXThreads , 1, 0, "POSIX thread support") LANGOPT(Blocks , 1, 0, "blocks extension to C") Index: include/clang/Driver/Options.td =================================================================== --- include/clang/Driver/Options.td +++ include/clang/Driver/Options.td @@ -604,6 +604,11 @@ def fast : Flag<["-"], "fast">, Group; def fasynchronous_unwind_tables : Flag<["-"], "fasynchronous-unwind-tables">, Group; +def fcattributes : Flag<["-"], "fc-attributes">, Group, + Flags<[DriverOption, CC1Option]>, HelpText<"Enable '[[]]' attributes in C">; +def fno_cattributes : Flag<["-"], "fno-c-attributes">, Group, + Flags<[DriverOption]>, HelpText<"Disable '[[]]' attributes in C">; + def fautolink : Flag <["-"], "fautolink">, Group; def fno_autolink : Flag <["-"], "fno-autolink">, Group, Flags<[DriverOption, CC1Option]>, Index: include/clang/Frontend/LangStandard.h =================================================================== --- include/clang/Frontend/LangStandard.h +++ include/clang/Frontend/LangStandard.h @@ -22,16 +22,17 @@ LineComment = (1 << 0), C99 = (1 << 1), C11 = (1 << 2), - CPlusPlus = (1 << 3), - CPlusPlus11 = (1 << 4), - CPlusPlus14 = (1 << 5), - CPlusPlus1z = (1 << 6), - CPlusPlus2a = (1 << 7), - Digraphs = (1 << 8), - GNUMode = (1 << 9), - HexFloat = (1 << 10), - ImplicitInt = (1 << 11), - OpenCL = (1 << 12) + C2x = (1 << 3), + CPlusPlus = (1 << 4), + CPlusPlus11 = (1 << 5), + CPlusPlus14 = (1 << 6), + CPlusPlus1z = (1 << 7), + CPlusPlus2a = (1 << 8), + Digraphs = (1 << 9), + GNUMode = (1 << 10), + HexFloat = (1 << 11), + ImplicitInt = (1 << 12), + OpenCL = (1 << 13) }; } @@ -70,6 +71,9 @@ /// isC11 - Language is a superset of C11. bool isC11() const { return Flags & frontend::C11; } + /// isC2x - Language is a superset of C2x. + bool isC2x() const { return Flags & frontend::C2x; } + /// isCPlusPlus - Language is a C++ variant. bool isCPlusPlus() const { return Flags & frontend::CPlusPlus; } Index: include/clang/Frontend/LangStandards.def =================================================================== --- include/clang/Frontend/LangStandards.def +++ include/clang/Frontend/LangStandards.def @@ -77,6 +77,11 @@ LineComment | C99 | C11 | Digraphs | GNUMode | HexFloat) LANGSTANDARD_ALIAS_DEPR(gnu11, "gnu1x") +// C2X modes +LANGSTANDARD(c2x, "c2x", + C, "Working draft for ISO C 202x", + LineComment | C99 | C11 | C2x | Digraphs | HexFloat) + // C++ modes LANGSTANDARD(cxx98, "c++98", CXX, "ISO C++ 1998 with amendments", Index: include/clang/Parse/Parser.h =================================================================== --- include/clang/Parse/Parser.h +++ include/clang/Parse/Parser.h @@ -2164,50 +2164,58 @@ private: void ParseBlockId(SourceLocation CaretLoc); - // Check for the start of a C++11 attribute-specifier-seq in a context where - // an attribute is not allowed. - bool CheckProhibitedCXX11Attribute() { + /// Are C++11 or C2x attributes enabled? + bool standardAttributesAllowed() const { + const LangOptions &LO = getLangOpts(); + return LO.CPlusPlus11 || (LO.C2x && LO.CAttributes); + } + + // Check for the start of an attribute-specifier-seq in a context where an + // attribute is not allowed. + bool CheckProhibitedAttribute() { assert(Tok.is(tok::l_square)); - if (!getLangOpts().CPlusPlus11 || NextToken().isNot(tok::l_square)) + if (!standardAttributesAllowed() || NextToken().isNot(tok::l_square)) return false; - return DiagnoseProhibitedCXX11Attribute(); + return DiagnoseProhibitedAttribute(); } - bool DiagnoseProhibitedCXX11Attribute(); - void CheckMisplacedCXX11Attribute(ParsedAttributesWithRange &Attrs, - SourceLocation CorrectLocation) { - if (!getLangOpts().CPlusPlus11) + + bool DiagnoseProhibitedAttribute(); + void CheckMisplacedAttribute(ParsedAttributesWithRange &Attrs, + SourceLocation CorrectLocation) { + if (!standardAttributesAllowed()) return; if ((Tok.isNot(tok::l_square) || NextToken().isNot(tok::l_square)) && Tok.isNot(tok::kw_alignas)) return; - DiagnoseMisplacedCXX11Attribute(Attrs, CorrectLocation); + DiagnoseMisplacedAttribute(Attrs, CorrectLocation); } - void DiagnoseMisplacedCXX11Attribute(ParsedAttributesWithRange &Attrs, - SourceLocation CorrectLocation); + void DiagnoseMisplacedAttribute(ParsedAttributesWithRange &Attrs, + SourceLocation CorrectLocation); void stripTypeAttributesOffDeclSpec(ParsedAttributesWithRange &Attrs, DeclSpec &DS, Sema::TagUseKind TUK); void ProhibitAttributes(ParsedAttributesWithRange &attrs) { - if (!attrs.Range.isValid()) return; + if (attrs.Range.isInvalid()) + return; DiagnoseProhibitedAttributes(attrs); attrs.clear(); } void DiagnoseProhibitedAttributes(ParsedAttributesWithRange &attrs); - // Forbid C++11 attributes that appear on certain syntactic - // locations which standard permits but we don't supported yet, - // for example, attributes appertain to decl specifiers. - void ProhibitCXX11Attributes(ParsedAttributesWithRange &Attrs, - unsigned DiagID); + // Forbid C++11 and C2x attributes that appear on certain syntactic locations + // which standard permits but we don't supported yet, for example, attributes + // appertain to decl specifiers. + void ProhibitAttributes(ParsedAttributesWithRange &Attrs, unsigned DiagID); - /// \brief Skip C++11 attributes and return the end location of the last one. + /// \brief Skip C++11 and C2x attributes and return the end location of the + /// last one. /// \returns SourceLocation() if there are no attributes. - SourceLocation SkipCXX11Attributes(); + SourceLocation SkipAttributes(); - /// \brief Diagnose and skip C++11 attributes that appear in syntactic + /// \brief Diagnose and skip C++11 and C2x attributes that appear in syntactic /// locations where attributes are not allowed. - void DiagnoseAndSkipCXX11Attributes(); + void DiagnoseAndSkipAttributes(); /// \brief Parses syntax-generic attribute arguments for attributes which are /// known to the implementation, and adds them to the given ParsedAttributes @@ -2254,43 +2262,41 @@ IdentifierInfo *ScopeName, SourceLocation ScopeLoc, AttributeList::Syntax Syntax); - void MaybeParseCXX11Attributes(Declarator &D) { - if (getLangOpts().CPlusPlus11 && isCXX11AttributeSpecifier()) { + void MaybeParseAttributes(Declarator &D) { + if (standardAttributesAllowed() && isAttributeSpecifier()) { ParsedAttributesWithRange attrs(AttrFactory); SourceLocation endLoc; - ParseCXX11Attributes(attrs, &endLoc); + ParseAttributes(attrs, &endLoc); D.takeAttributes(attrs, endLoc); } } - void MaybeParseCXX11Attributes(ParsedAttributes &attrs, - SourceLocation *endLoc = nullptr) { - if (getLangOpts().CPlusPlus11 && isCXX11AttributeSpecifier()) { + void MaybeParseAttributes(ParsedAttributes &attrs, + SourceLocation *endLoc = nullptr) { + if (standardAttributesAllowed() && isAttributeSpecifier()) { ParsedAttributesWithRange attrsWithRange(AttrFactory); - ParseCXX11Attributes(attrsWithRange, endLoc); + ParseAttributes(attrsWithRange, endLoc); attrs.takeAllFrom(attrsWithRange); } } - void MaybeParseCXX11Attributes(ParsedAttributesWithRange &attrs, - SourceLocation *endLoc = nullptr, - bool OuterMightBeMessageSend = false) { - if (getLangOpts().CPlusPlus11 && - isCXX11AttributeSpecifier(false, OuterMightBeMessageSend)) - ParseCXX11Attributes(attrs, endLoc); + void MaybeParseAttributes(ParsedAttributesWithRange &attrs, + SourceLocation *endLoc = nullptr, + bool OuterMightBeMessageSend = false) { + if (standardAttributesAllowed() && + isAttributeSpecifier(false, OuterMightBeMessageSend)) + ParseAttributes(attrs, endLoc); } - void ParseCXX11AttributeSpecifier(ParsedAttributes &attrs, - SourceLocation *EndLoc = nullptr); - void ParseCXX11Attributes(ParsedAttributesWithRange &attrs, - SourceLocation *EndLoc = nullptr); - /// \brief Parses a C++-style attribute argument list. Returns true if this - /// results in adding an attribute to the ParsedAttributes list. - bool ParseCXX11AttributeArgs(IdentifierInfo *AttrName, - SourceLocation AttrNameLoc, - ParsedAttributes &Attrs, SourceLocation *EndLoc, - IdentifierInfo *ScopeName, - SourceLocation ScopeLoc); + void ParseAttributeSpecifier(ParsedAttributes &attrs, + SourceLocation *EndLoc = nullptr); + void ParseAttributes(ParsedAttributesWithRange &attrs, + SourceLocation *EndLoc = nullptr); + /// \brief Parses a C++11 (or C2x)-style attribute argument list. Returns true + /// if this results in adding an attribute to the ParsedAttributes list. + bool ParseAttributeArgs(IdentifierInfo *AttrName, SourceLocation AttrNameLoc, + ParsedAttributes &Attrs, SourceLocation *EndLoc, + IdentifierInfo *ScopeName, SourceLocation ScopeLoc); - IdentifierInfo *TryParseCXX11AttributeIdentifier(SourceLocation &Loc); + IdentifierInfo *TryParseAttributeIdentifier(SourceLocation &Loc); void MaybeParseMicrosoftAttributes(ParsedAttributes &attrs, SourceLocation *endLoc = nullptr) { @@ -2489,9 +2495,8 @@ /// is ill-formed by C++11 [dcl.attr.grammar]p6. CAK_InvalidAttributeSpecifier }; - CXX11AttributeKind - isCXX11AttributeSpecifier(bool Disambiguate = false, - bool OuterMightBeMessageSend = false); + CXX11AttributeKind isAttributeSpecifier(bool Disambiguate = false, + bool OuterMightBeMessageSend = false); void DiagnoseUnexpectedNamespace(NamedDecl *Context); Index: include/clang/Sema/AttributeList.h =================================================================== --- include/clang/Sema/AttributeList.h +++ include/clang/Sema/AttributeList.h @@ -100,6 +100,8 @@ AS_GNU, /// [[...]] AS_CXX11, + /// [[...]] + AS_C2x, /// __declspec(...) AS_Declspec, /// [uuid("...")] class Foo @@ -378,6 +380,9 @@ bool isCXX11Attribute() const { return SyntaxUsed == AS_CXX11 || isAlignasAttribute(); } + bool isC2xAttribute() const { + return SyntaxUsed == AS_C2x; + } bool isKeywordAttribute() const { return SyntaxUsed == AS_Keyword || SyntaxUsed == AS_ContextSensitiveKeyword; } Index: lib/Frontend/CompilerInvocation.cpp =================================================================== --- lib/Frontend/CompilerInvocation.cpp +++ lib/Frontend/CompilerInvocation.cpp @@ -1726,6 +1726,7 @@ Opts.LineComment = Std.hasLineComments(); Opts.C99 = Std.isC99(); Opts.C11 = Std.isC11(); + Opts.C2x = Std.isC2x(); Opts.CPlusPlus = Std.isCPlusPlus(); Opts.CPlusPlus11 = Std.isCPlusPlus11(); Opts.CPlusPlus14 = Std.isCPlusPlus14(); @@ -2134,6 +2135,7 @@ && Opts.OpenCLVersion >= 200); Opts.BlocksRuntimeOptional = Args.hasArg(OPT_fblocks_runtime_optional); Opts.CoroutinesTS = Args.hasArg(OPT_fcoroutines_ts); + Opts.CAttributes = Args.hasArg(OPT_fcattributes); Opts.ModulesTS = Args.hasArg(OPT_fmodules_ts); Opts.Modules = Args.hasArg(OPT_fmodules) || Opts.ModulesTS; Opts.ModulesStrictDeclUse = Args.hasArg(OPT_fmodules_strict_decluse); Index: lib/Lex/Lexer.cpp =================================================================== --- lib/Lex/Lexer.cpp +++ lib/Lex/Lexer.cpp @@ -3612,7 +3612,7 @@ if (LangOpts.Digraphs && Char == '>') { Kind = tok::r_square; // ':>' -> ']' CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); - } else if (LangOpts.CPlusPlus && Char == ':') { + } else if ((LangOpts.CPlusPlus || LangOpts.C2x) && Char == ':') { Kind = tok::coloncolon; CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); } else { Index: lib/Parse/ParseDecl.cpp =================================================================== --- lib/Parse/ParseDecl.cpp +++ lib/Parse/ParseDecl.cpp @@ -1509,10 +1509,10 @@ /// \return \c true if we skipped an attribute-like chunk of tokens, \c false if /// this doesn't appear to actually be an attribute-specifier, and the caller /// should try to parse it. -bool Parser::DiagnoseProhibitedCXX11Attribute() { +bool Parser::DiagnoseProhibitedAttribute() { assert(Tok.is(tok::l_square) && NextToken().is(tok::l_square)); - switch (isCXX11AttributeSpecifier(/*Disambiguate*/true)) { + switch (isAttributeSpecifier(/*Disambiguate*/true)) { case CAK_NotAttributeSpecifier: // No diagnostic: we're in Obj-C++11 and this is not actually an attribute. return false; @@ -1539,28 +1539,27 @@ /// attribute-specifier in a location where an attribute is not permitted, but /// we know where the attributes ought to be written. Parse them anyway, and /// provide a fixit moving them to the right place. -void Parser::DiagnoseMisplacedCXX11Attribute(ParsedAttributesWithRange &Attrs, - SourceLocation CorrectLocation) { +void Parser::DiagnoseMisplacedAttribute(ParsedAttributesWithRange &Attrs, + SourceLocation CorrectLocation) { assert((Tok.is(tok::l_square) && NextToken().is(tok::l_square)) || Tok.is(tok::kw_alignas)); // Consume the attributes. SourceLocation Loc = Tok.getLocation(); - ParseCXX11Attributes(Attrs); + ParseAttributes(Attrs); CharSourceRange AttrRange(SourceRange(Loc, Attrs.Range.getEnd()), true); Diag(Loc, diag::err_attributes_not_allowed) - << FixItHint::CreateInsertionFromRange(CorrectLocation, AttrRange) - << FixItHint::CreateRemoval(AttrRange); + << FixItHint::CreateInsertionFromRange(CorrectLocation, AttrRange) + << FixItHint::CreateRemoval(AttrRange); } void Parser::DiagnoseProhibitedAttributes(ParsedAttributesWithRange &attrs) { - Diag(attrs.Range.getBegin(), diag::err_attributes_not_allowed) - << attrs.Range; + Diag(attrs.Range.getBegin(), diag::err_attributes_not_allowed) << attrs.Range; } -void Parser::ProhibitCXX11Attributes(ParsedAttributesWithRange &Attrs, - unsigned DiagID) { +void Parser::ProhibitAttributes(ParsedAttributesWithRange &Attrs, + unsigned DiagID) { for (AttributeList *Attr = Attrs.getList(); Attr; Attr = Attr->getNext()) { if (!Attr->isCXX11Attribute()) continue; @@ -1568,8 +1567,7 @@ Diag(Attr->getLoc(), diag::warn_unknown_attribute_ignored) << Attr->getName(); else { - Diag(Attr->getLoc(), DiagID) - << Attr->getName(); + Diag(Attr->getLoc(), DiagID) << Attr->getName(); Attr->setInvalid(); } } @@ -2893,7 +2891,7 @@ // Reject C++11 attributes that appertain to decl specifiers as // we don't support any C++11 attributes that appertain to decl // specifiers. This also conforms to what g++ 4.8 is doing. - ProhibitCXX11Attributes(attrs, diag::err_attribute_not_type_attr); + ProhibitAttributes(attrs, diag::err_attribute_not_type_attr); DS.takeAttributesFrom(attrs); } @@ -2905,7 +2903,7 @@ case tok::l_square: case tok::kw_alignas: - if (!getLangOpts().CPlusPlus11 || !isCXX11AttributeSpecifier()) + if (!standardAttributesAllowed() || !isAttributeSpecifier()) goto DoneWithDeclSpec; ProhibitAttributes(attrs); @@ -2915,7 +2913,7 @@ attrs.clear(); attrs.Range = SourceRange(); - ParseCXX11Attributes(attrs); + ParseAttributes(attrs); AttrsLastTime = true; continue; @@ -3754,7 +3752,8 @@ /// semicolon. /// /// struct-declaration: -/// specifier-qualifier-list struct-declarator-list +/// [C2x] attributes-specifier-seq[opt] +/// specifier-qualifier-list struct-declarator-list /// [GNU] __extension__ struct-declaration /// [GNU] specifier-qualifier-list /// struct-declarator-list: @@ -3778,6 +3777,11 @@ return ParseStructDeclaration(DS, FieldsCallback); } + // Parse leading attributes. + ParsedAttributesWithRange Attrs(AttrFactory); + MaybeParseAttributes(Attrs); + DS.takeAttributesFrom(Attrs); + // Parse the common specifier-qualifiers-list piece. ParseSpecifierQualifierList(DS); @@ -4004,7 +4008,7 @@ // If attributes exist after tag, parse them. ParsedAttributesWithRange attrs(AttrFactory); MaybeParseGNUAttributes(attrs); - MaybeParseCXX11Attributes(attrs); + MaybeParseAttributes(attrs); MaybeParseMicrosoftDeclSpecs(attrs); SourceLocation ScopedEnumKWLoc; @@ -4023,7 +4027,7 @@ // They are allowed afterwards, though. MaybeParseGNUAttributes(attrs); - MaybeParseCXX11Attributes(attrs); + MaybeParseAttributes(attrs); MaybeParseMicrosoftDeclSpecs(attrs); } @@ -4209,6 +4213,10 @@ PP.EnterToken(Tok); Tok.setKind(tok::semi); } + + // Attributes are prohibited in this location in C2x (and forward + // declarations are prohibited in C++). + ProhibitAttributes(attrs); } else { TUK = Sema::TUK_Reference; } @@ -4388,11 +4396,11 @@ ParsedAttributesWithRange attrs(AttrFactory); MaybeParseGNUAttributes(attrs); ProhibitAttributes(attrs); // GNU-style attributes are prohibited. - if (getLangOpts().CPlusPlus11 && isCXX11AttributeSpecifier()) { + if (standardAttributesAllowed() && isAttributeSpecifier()) { if (!getLangOpts().CPlusPlus1z) Diag(Tok.getLocation(), diag::warn_cxx14_compat_attribute) << 1 /*enumerator*/; - ParseCXX11Attributes(attrs); + ParseAttributes(attrs); } SourceLocation EqualLoc; @@ -4868,7 +4876,7 @@ // There may be attributes here, appertaining to the constructor name or type // we just stepped past. - SkipCXX11Attributes(); + SkipAttributes(); // Current class name must be followed by a left parenthesis. if (Tok.isNot(tok::l_paren)) { @@ -4888,7 +4896,7 @@ // A C++11 attribute here signals that we have a constructor, and is an // attribute on the first constructor parameter. if (getLangOpts().CPlusPlus11 && - isCXX11AttributeSpecifier(/*Disambiguate*/ false, + isAttributeSpecifier(/*Disambiguate*/ false, /*OuterMightBeMessageSend*/ true)) { TPA.Revert(); return true; @@ -4941,7 +4949,7 @@ // Skip past the right-paren and any following attributes to get to // the function body or trailing-return-type. ConsumeParen(); - SkipCXX11Attributes(); + SkipAttributes(); if (DeductionGuide) { // C(X) -> ... is a deduction guide. @@ -4997,10 +5005,10 @@ DeclSpec &DS, unsigned AttrReqs, bool AtomicAllowed, bool IdentifierRequired, Optional> CodeCompletionHandler) { - if (getLangOpts().CPlusPlus11 && (AttrReqs & AR_CXX11AttributesParsed) && - isCXX11AttributeSpecifier()) { + if (standardAttributesAllowed() && (AttrReqs & AR_CXX11AttributesParsed) && + isAttributeSpecifier()) { ParsedAttributesWithRange attrs(AttrFactory); - ParseCXX11Attributes(attrs); + ParseAttributes(attrs); DS.takeAttributesFrom(attrs); } @@ -5674,7 +5682,7 @@ // Don't parse attributes unless we have parsed an unparenthesized name. if (D.hasName() && !D.getNumTypeObjects()) - MaybeParseCXX11Attributes(D); + MaybeParseAttributes(D); while (1) { if (Tok.is(tok::l_paren)) { @@ -5835,7 +5843,7 @@ (getLangOpts().CPlusPlus && Tok.is(tok::ellipsis) && NextToken().is(tok::r_paren)) || // C++ int(...) isDeclarationSpecifier() || // 'int(int)' is a function. - isCXX11AttributeSpecifier()) { // 'int([[]]int)' is a function. + isAttributeSpecifier()) { // 'int([[]]int)' is a function. // This handles C99 6.7.5.3p11: in "typedef int X; void foo(X)", X is // considered to be a type, not a K&R identifier-list. isGrouping = false; @@ -5934,7 +5942,7 @@ SmallVector DynamicExceptionRanges; ExprResult NoexceptExpr; CachedTokens *ExceptionSpecTokens = nullptr; - ParsedAttributes FnAttrs(AttrFactory); + ParsedAttributesWithRange FnAttrs(AttrFactory); TypeResult TrailingReturnType; /* LocalEndLoc is the end location for the local FunctionTypeLoc. @@ -5955,6 +5963,11 @@ RParenLoc = Tracker.getCloseLocation(); LocalEndLoc = RParenLoc; EndLoc = RParenLoc; + + // If there are attributes following the identifier list, parse them and + // prohibit them. + MaybeParseAttributes(FnAttrs); + ProhibitAttributes(FnAttrs); } else { if (Tok.isNot(tok::r_paren)) ParseParameterDeclarationClause(D, FirstArgAttrs, ParamInfo, @@ -6047,7 +6060,7 @@ // Parse attribute-specifier-seq[opt]. Per DR 979 and DR 1297, this goes // after the exception-specification. - MaybeParseCXX11Attributes(FnAttrs); + MaybeParseAttributes(FnAttrs); // Parse trailing-return-type[opt]. LocalEndLoc = EndLoc; @@ -6060,6 +6073,8 @@ TrailingReturnType = ParseTrailingReturnType(Range); EndLoc = Range.getEnd(); } + } else if (standardAttributesAllowed()) { + MaybeParseAttributes(FnAttrs); } } @@ -6248,7 +6263,7 @@ DeclSpec DS(AttrFactory); // Parse any C++11 attributes. - MaybeParseCXX11Attributes(DS.getAttributes()); + MaybeParseAttributes(DS.getAttributes()); // Skip any Microsoft attributes before a param. MaybeParseMicrosoftAttributes(DS.getAttributes()); @@ -6405,7 +6420,7 @@ /// [C++11] direct-declarator '[' constant-expression[opt] ']' /// attribute-specifier-seq[opt] void Parser::ParseBracketDeclarator(Declarator &D) { - if (CheckProhibitedCXX11Attribute()) + if (CheckProhibitedAttribute()) return; BalancedDelimiterTracker T(*this, tok::l_square); @@ -6416,7 +6431,7 @@ if (Tok.getKind() == tok::r_square) { T.consumeClose(); ParsedAttributes attrs(AttrFactory); - MaybeParseCXX11Attributes(attrs); + MaybeParseAttributes(attrs); // Remember that we parsed the empty array type. D.AddTypeInfo(DeclaratorChunk::getArray(0, false, false, nullptr, @@ -6432,7 +6447,7 @@ T.consumeClose(); ParsedAttributes attrs(AttrFactory); - MaybeParseCXX11Attributes(attrs); + MaybeParseAttributes(attrs); // Remember that we parsed a array type, and remember its features. D.AddTypeInfo(DeclaratorChunk::getArray(0, false, false, @@ -6509,7 +6524,7 @@ T.consumeClose(); - MaybeParseCXX11Attributes(DS.getAttributes()); + MaybeParseAttributes(DS.getAttributes()); // Remember that we parsed a array type, and remember its features. D.AddTypeInfo(DeclaratorChunk::getArray(DS.getTypeQualifiers(), Index: lib/Parse/ParseDeclCXX.cpp =================================================================== --- lib/Parse/ParseDeclCXX.cpp +++ lib/Parse/ParseDeclCXX.cpp @@ -76,12 +76,12 @@ ParsedAttributesWithRange attrs(AttrFactory); SourceLocation attrLoc; - if (getLangOpts().CPlusPlus11 && isCXX11AttributeSpecifier()) { + if (getLangOpts().CPlusPlus11 && isAttributeSpecifier()) { if (!getLangOpts().CPlusPlus1z) Diag(Tok.getLocation(), diag::warn_cxx14_compat_attribute) << 0 /*namespace*/; attrLoc = Tok.getLocation(); - ParseCXX11Attributes(attrs); + ParseAttributes(attrs); } if (Tok.is(tok::identifier)) { @@ -216,7 +216,7 @@ while (!tryParseMisplacedModuleImport() && Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { ParsedAttributesWithRange attrs(AttrFactory); - MaybeParseCXX11Attributes(attrs); + MaybeParseAttributes(attrs); ParseExternalDeclaration(attrs); } @@ -319,7 +319,7 @@ Tok.is(tok::l_brace) ? Tok.getLocation() : SourceLocation()); ParsedAttributesWithRange attrs(AttrFactory); - MaybeParseCXX11Attributes(attrs); + MaybeParseAttributes(attrs); if (Tok.isNot(tok::l_brace)) { // Reset the source range in DS, as the leading "extern" @@ -369,7 +369,7 @@ // Fall through. default: ParsedAttributesWithRange attrs(AttrFactory); - MaybeParseCXX11Attributes(attrs); + MaybeParseAttributes(attrs); ParseExternalDeclaration(attrs); continue; } @@ -401,7 +401,7 @@ if (Tok.isNot(tok::l_brace)) { // FIXME: Factor out a ParseExternalDeclarationWithAttrs. ParsedAttributesWithRange Attrs(AttrFactory); - MaybeParseCXX11Attributes(Attrs); + MaybeParseAttributes(Attrs); MaybeParseMicrosoftAttributes(Attrs); ParseExternalDeclaration(Attrs); return Actions.ActOnFinishExportDecl(getCurScope(), ExportDecl, @@ -420,7 +420,7 @@ while (!tryParseMisplacedModuleImport() && Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { ParsedAttributesWithRange Attrs(AttrFactory); - MaybeParseCXX11Attributes(Attrs); + MaybeParseAttributes(Attrs); MaybeParseMicrosoftAttributes(Attrs); ParseExternalDeclaration(Attrs); } @@ -635,14 +635,14 @@ // Check for misplaced attributes before the identifier in an // alias-declaration. ParsedAttributesWithRange MisplacedAttrs(AttrFactory); - MaybeParseCXX11Attributes(MisplacedAttrs); + MaybeParseAttributes(MisplacedAttrs); UsingDeclarator D; bool InvalidDeclarator = ParseUsingDeclarator(Context, D); ParsedAttributesWithRange Attrs(AttrFactory); MaybeParseGNUAttributes(Attrs); - MaybeParseCXX11Attributes(Attrs); + MaybeParseAttributes(Attrs); // Maybe this is an alias-declaration. if (Tok.is(tok::equal)) { @@ -1397,7 +1397,7 @@ // If C++0x attributes exist here, parse them. // FIXME: Are we consistent with the ordering of parsing of different // styles of attributes? - MaybeParseCXX11Attributes(attrs); + MaybeParseAttributes(attrs); // Source location used by FIXIT to insert misplaced // C++11 attributes @@ -1614,7 +1614,7 @@ // For these, DSC is DSC_type_specifier or DSC_alias_declaration. // If there are attributes after class name, parse them. - MaybeParseCXX11Attributes(Attributes); + MaybeParseAttributes(Attributes); const PrintingPolicy &Policy = Actions.getASTContext().getPrintingPolicy(); Sema::TagUseKind TUK; @@ -2028,20 +2028,20 @@ SourceLocation StartLoc = Tok.getLocation(); ParsedAttributesWithRange Attributes(AttrFactory); - MaybeParseCXX11Attributes(Attributes); + MaybeParseAttributes(Attributes); // Parse the 'virtual' keyword. if (TryConsumeToken(tok::kw_virtual)) IsVirtual = true; - CheckMisplacedCXX11Attribute(Attributes, StartLoc); + CheckMisplacedAttribute(Attributes, StartLoc); // Parse an (optional) access specifier. AccessSpecifier Access = getAccessSpecifierIfPresent(); if (Access != AS_none) ConsumeToken(); - CheckMisplacedCXX11Attribute(Attributes, StartLoc); + CheckMisplacedAttribute(Attributes, StartLoc); // Parse the 'virtual' keyword (again!), in case it came after the // access specifier. @@ -2056,7 +2056,7 @@ IsVirtual = true; } - CheckMisplacedCXX11Attribute(Attributes, StartLoc); + CheckMisplacedAttribute(Attributes, StartLoc); // Parse the class-name. @@ -2523,7 +2523,7 @@ ParsedAttributesWithRange attrs(AttrFactory); ParsedAttributesWithRange FnAttrs(AttrFactory); // Optional C++11 attribute-specifier - MaybeParseCXX11Attributes(attrs); + MaybeParseAttributes(attrs); // We need to keep these attributes for future diagnostic // before they are taken over by declaration specifier. FnAttrs.addAll(attrs.getList()); @@ -2958,7 +2958,7 @@ // Diagnose any C++11 attributes after 'final' keyword. // We deliberately discard these attributes. ParsedAttributesWithRange Attrs(AttrFactory); - CheckMisplacedCXX11Attribute(Attrs, AttrFixitLoc); + CheckMisplacedAttribute(Attrs, AttrFixitLoc); // This can only happen if we had malformed misplaced attributes; // we only get called if there is a colon or left-brace after the @@ -3177,7 +3177,7 @@ // These attributes are not allowed to appear here, // and the only possible place for them to appertain // to the class would be between class-key and class-name. - CheckMisplacedCXX11Attribute(Attrs, AttrFixitLoc); + CheckMisplacedAttribute(Attrs, AttrFixitLoc); // ParseClassSpecifier() does only a superficial check for attributes before // deciding to call this method. For example, for @@ -3775,7 +3775,7 @@ /// If a keyword or an alternative token that satisfies the syntactic /// requirements of an identifier is contained in an attribute-token, /// it is considered an identifier. -IdentifierInfo *Parser::TryParseCXX11AttributeIdentifier(SourceLocation &Loc) { +IdentifierInfo *Parser::TryParseAttributeIdentifier(SourceLocation &Loc) { switch (Tok.getKind()) { default: // Identifiers and keywords have identifier info attached. @@ -3813,7 +3813,7 @@ } static bool IsBuiltInOrStandardCXX11Attribute(IdentifierInfo *AttrName, - IdentifierInfo *ScopeName) { + IdentifierInfo *ScopeName) { switch (AttributeList::getKind(AttrName, ScopeName, AttributeList::AS_CXX11)) { case AttributeList::AT_CarriesDependency: @@ -3844,19 +3844,22 @@ /// '[' balanced-token-seq ']' /// '{' balanced-token-seq '}' /// any token but '(', ')', '[', ']', '{', or '}' -bool Parser::ParseCXX11AttributeArgs(IdentifierInfo *AttrName, - SourceLocation AttrNameLoc, - ParsedAttributes &Attrs, - SourceLocation *EndLoc, - IdentifierInfo *ScopeName, - SourceLocation ScopeLoc) { +bool Parser::ParseAttributeArgs(IdentifierInfo *AttrName, + SourceLocation AttrNameLoc, + ParsedAttributes &Attrs, SourceLocation *EndLoc, + IdentifierInfo *ScopeName, + SourceLocation ScopeLoc) { assert(Tok.is(tok::l_paren) && "Not a C++11 attribute argument list"); SourceLocation LParenLoc = Tok.getLocation(); + AttributeList::Syntax Syntax = getLangOpts().CPlusPlus11 + ? AttributeList::AS_CXX11 + : AttributeList::AS_C2x; // If the attribute isn't known, we will not attempt to parse any // arguments. - if (!hasAttribute(AttrSyntax::CXX, ScopeName, AttrName, - getTargetInfo(), getLangOpts())) { + if (!hasAttribute(getLangOpts().CPlusPlus11 ? AttrSyntax::CXX + : AttrSyntax::C2x, + ScopeName, AttrName, getTargetInfo(), getLangOpts())) { // Eat the left paren, then skip to the ending right paren. ConsumeParen(); SkipUntil(tok::r_paren); @@ -3867,7 +3870,7 @@ // GNU-scoped attributes have some special cases to handle GNU-specific // behaviors. ParseGNUAttributeArgs(AttrName, AttrNameLoc, Attrs, EndLoc, ScopeName, - ScopeLoc, AttributeList::AS_CXX11, nullptr); + ScopeLoc, Syntax, nullptr); return true; } @@ -3876,11 +3879,11 @@ if (ScopeName && ScopeName->getName() == "clang") NumArgs = ParseClangAttributeArgs(AttrName, AttrNameLoc, Attrs, EndLoc, ScopeName, - ScopeLoc, AttributeList::AS_CXX11); + ScopeLoc, Syntax); else NumArgs = ParseAttributeArgsCommon(AttrName, AttrNameLoc, Attrs, EndLoc, - ScopeName, ScopeLoc, AttributeList::AS_CXX11); + ScopeName, ScopeLoc, Syntax); const AttributeList *Attr = Attrs.getList(); if (Attr && IsBuiltInOrStandardCXX11Attribute(AttrName, ScopeName)) { @@ -3906,7 +3909,7 @@ return true; } -/// ParseCXX11AttributeSpecifier - Parse a C++11 attribute-specifier. +/// ParseAttributeSpecifier - Parse a C++11 or C2x attribute-specifier. /// /// [C++11] attribute-specifier: /// '[' '[' attribute-list ']' ']' @@ -3930,31 +3933,33 @@ /// /// [C++11] attribute-namespace: /// identifier -void Parser::ParseCXX11AttributeSpecifier(ParsedAttributes &attrs, - SourceLocation *endLoc) { - if (Tok.is(tok::kw_alignas)) { +void Parser::ParseAttributeSpecifier(ParsedAttributes &attrs, + SourceLocation *endLoc) { + bool CXXAttr = getLangOpts().CPlusPlus11; + if (CXXAttr && Tok.is(tok::kw_alignas)) { Diag(Tok.getLocation(), diag::warn_cxx98_compat_alignas); ParseAlignmentSpecifier(attrs, endLoc); return; } - assert(Tok.is(tok::l_square) && NextToken().is(tok::l_square) - && "Not a C++11 attribute list"); + assert(Tok.is(tok::l_square) && NextToken().is(tok::l_square) && + "Not a standards-based attribute list"); - Diag(Tok.getLocation(), diag::warn_cxx98_compat_attribute); + Diag(Tok.getLocation(), CXXAttr ? diag::warn_cxx98_compat_attribute + : diag::warn_c11_compat_attribute); ConsumeBracket(); ConsumeBracket(); SourceLocation CommonScopeLoc; IdentifierInfo *CommonScopeName = nullptr; - if (Tok.is(tok::kw_using)) { + if (CXXAttr && Tok.is(tok::kw_using)) { Diag(Tok.getLocation(), getLangOpts().CPlusPlus1z ? diag::warn_cxx14_compat_using_attribute_ns : diag::ext_using_attribute_ns); ConsumeToken(); - CommonScopeName = TryParseCXX11AttributeIdentifier(CommonScopeLoc); + CommonScopeName = TryParseAttributeIdentifier(CommonScopeLoc); if (!CommonScopeName) { Diag(Tok.getLocation(), diag::err_expected) << tok::identifier; SkipUntil(tok::r_square, tok::colon, StopBeforeMatch); @@ -3963,7 +3968,7 @@ Diag(Tok.getLocation(), diag::err_expected) << tok::colon; } - llvm::SmallDenseMap SeenAttrs; + llvm::SmallDenseMap SeenAttrs; while (Tok.isNot(tok::r_square)) { // attribute not present @@ -3973,7 +3978,7 @@ SourceLocation ScopeLoc, AttrLoc; IdentifierInfo *ScopeName = nullptr, *AttrName = nullptr; - AttrName = TryParseCXX11AttributeIdentifier(AttrLoc); + AttrName = TryParseAttributeIdentifier(AttrLoc); if (!AttrName) // Break out to the "expected ']'" diagnostic. break; @@ -3983,7 +3988,7 @@ ScopeName = AttrName; ScopeLoc = AttrLoc; - AttrName = TryParseCXX11AttributeIdentifier(AttrLoc); + AttrName = TryParseAttributeIdentifier(AttrLoc); if (!AttrName) { Diag(Tok.getLocation(), diag::err_expected) << tok::identifier; SkipUntil(tok::r_square, tok::comma, StopAtSemi | StopBeforeMatch); @@ -4011,18 +4016,19 @@ // Parse attribute arguments if (Tok.is(tok::l_paren)) - AttrParsed = ParseCXX11AttributeArgs(AttrName, AttrLoc, attrs, endLoc, - ScopeName, ScopeLoc); + AttrParsed = ParseAttributeArgs(AttrName, AttrLoc, attrs, endLoc, + ScopeName, ScopeLoc); if (!AttrParsed) - attrs.addNew(AttrName, - SourceRange(ScopeLoc.isValid() ? ScopeLoc : AttrLoc, - AttrLoc), - ScopeName, ScopeLoc, nullptr, 0, AttributeList::AS_CXX11); + attrs.addNew( + AttrName, + SourceRange(ScopeLoc.isValid() ? ScopeLoc : AttrLoc, AttrLoc), + ScopeName, ScopeLoc, nullptr, 0, + CXXAttr ? AttributeList::AS_CXX11 : AttributeList::AS_C2x); if (TryConsumeToken(tok::ellipsis)) Diag(Tok, diag::err_cxx11_attribute_forbids_ellipsis) - << AttrName->getName(); + << AttrName->getName(); } if (ExpectAndConsume(tok::r_square)) @@ -4033,41 +4039,40 @@ SkipUntil(tok::r_square); } -/// ParseCXX11Attributes - Parse a C++11 attribute-specifier-seq. +/// ParseAttributes - Parse a C++11 or C2x attribute-specifier-seq. /// /// attribute-specifier-seq: /// attribute-specifier-seq[opt] attribute-specifier -void Parser::ParseCXX11Attributes(ParsedAttributesWithRange &attrs, - SourceLocation *endLoc) { - assert(getLangOpts().CPlusPlus11); +void Parser::ParseAttributes(ParsedAttributesWithRange &attrs, + SourceLocation *endLoc) { + assert(standardAttributesAllowed()); SourceLocation StartLoc = Tok.getLocation(), Loc; if (!endLoc) endLoc = &Loc; do { - ParseCXX11AttributeSpecifier(attrs, endLoc); - } while (isCXX11AttributeSpecifier()); + ParseAttributeSpecifier(attrs, endLoc); + } while (isAttributeSpecifier()); attrs.Range = SourceRange(StartLoc, *endLoc); } -void Parser::DiagnoseAndSkipCXX11Attributes() { +void Parser::DiagnoseAndSkipAttributes() { // Start and end location of an attribute or an attribute list. SourceLocation StartLoc = Tok.getLocation(); - SourceLocation EndLoc = SkipCXX11Attributes(); + SourceLocation EndLoc = SkipAttributes(); if (EndLoc.isValid()) { SourceRange Range(StartLoc, EndLoc); - Diag(StartLoc, diag::err_attributes_not_allowed) - << Range; + Diag(StartLoc, diag::err_attributes_not_allowed) << Range; } } -SourceLocation Parser::SkipCXX11Attributes() { +SourceLocation Parser::SkipAttributes() { SourceLocation EndLoc; - if (!isCXX11AttributeSpecifier()) + if (!isAttributeSpecifier()) return EndLoc; do { @@ -4084,7 +4089,7 @@ T.skipToEnd(); EndLoc = T.getCloseLocation(); } - } while (isCXX11AttributeSpecifier()); + } while (isAttributeSpecifier()); return EndLoc; } Index: lib/Parse/ParseExpr.cpp =================================================================== --- lib/Parse/ParseExpr.cpp +++ lib/Parse/ParseExpr.cpp @@ -1503,7 +1503,7 @@ // Reject array indices starting with a lambda-expression. '[[' is // reserved for attributes. - if (CheckProhibitedCXX11Attribute()) { + if (CheckProhibitedAttribute()) { (void)Actions.CorrectDelayedTyposInExpr(LHS); return ExprError(); } @@ -2083,7 +2083,7 @@ Comps.back().LocEnd = ConsumeToken(); } else if (Tok.is(tok::l_square)) { - if (CheckProhibitedCXX11Attribute()) + if (CheckProhibitedAttribute()) return ExprError(); // offsetof-member-designator: offsetof-member-design '[' expression ']' Index: lib/Parse/ParseExprCXX.cpp =================================================================== --- lib/Parse/ParseExprCXX.cpp +++ lib/Parse/ParseExprCXX.cpp @@ -1168,7 +1168,7 @@ DeclEndLoc = ESpecRange.getEnd(); // Parse attribute-specifier[opt]. - MaybeParseCXX11Attributes(Attr, &DeclEndLoc); + MaybeParseAttributes(Attr, &DeclEndLoc); SourceLocation FunLocalRangeEnd = DeclEndLoc; @@ -1241,7 +1241,7 @@ } // Parse attribute-specifier[opt]. - MaybeParseCXX11Attributes(Attr, &DeclEndLoc); + MaybeParseAttributes(Attr, &DeclEndLoc); // Parse the return type, if there is one. if (Tok.is(tok::arrow)) { @@ -1732,7 +1732,7 @@ } ParsedAttributesWithRange attrs(AttrFactory); - MaybeParseCXX11Attributes(attrs); + MaybeParseAttributes(attrs); // Determine what kind of thing we have. switch (isCXXConditionDeclarationOrInitStatement(InitStmt)) { @@ -2802,7 +2802,7 @@ bool first = true; while (Tok.is(tok::l_square)) { // An array-size expression can't start with a lambda. - if (CheckProhibitedCXX11Attribute()) + if (CheckProhibitedAttribute()) continue; BalancedDelimiterTracker T(*this, tok::l_square); @@ -2821,7 +2821,7 @@ // Attributes here appertain to the array type. C++11 [expr.new]p5. ParsedAttributes Attrs(AttrFactory); - MaybeParseCXX11Attributes(Attrs); + MaybeParseAttributes(Attrs); D.AddTypeInfo(DeclaratorChunk::getArray(0, /*static=*/false, /*star=*/false, Index: lib/Parse/ParseObjc.cpp =================================================================== --- lib/Parse/ParseObjc.cpp +++ lib/Parse/ParseObjc.cpp @@ -2219,7 +2219,7 @@ ObjCImplParsingDataRAII ObjCImplParsing(*this, ObjCImpDecl); while (!ObjCImplParsing.isFinished() && !isEofOrEom()) { ParsedAttributesWithRange attrs(AttrFactory); - MaybeParseCXX11Attributes(attrs); + MaybeParseAttributes(attrs); if (DeclGroupPtrTy DGP = ParseExternalDeclaration(attrs)) { DeclGroupRef DG = DGP.get(); DeclsInGroup.append(DG.begin(), DG.end()); Index: lib/Parse/ParseOpenMP.cpp =================================================================== --- lib/Parse/ParseOpenMP.cpp +++ lib/Parse/ParseOpenMP.cpp @@ -625,7 +625,7 @@ // Here we expect to see some function declaration. if (AS == AS_none) { assert(TagType == DeclSpec::TST_unspecified); - MaybeParseCXX11Attributes(Attrs); + MaybeParseAttributes(Attrs); ParsingDeclSpec PDS(*this); Ptr = ParseExternalDeclaration(Attrs, &PDS); } else { @@ -686,7 +686,7 @@ while (DKind != OMPD_end_declare_target && DKind != OMPD_declare_target && Tok.isNot(tok::eof) && Tok.isNot(tok::r_brace)) { ParsedAttributesWithRange attrs(AttrFactory); - MaybeParseCXX11Attributes(attrs); + MaybeParseAttributes(attrs); ParseExternalDeclaration(attrs); if (Tok.isAnnotation() && Tok.is(tok::annot_pragma_openmp)) { TentativeParsingAction TPA(*this); Index: lib/Parse/ParsePragma.cpp =================================================================== --- lib/Parse/ParsePragma.cpp +++ lib/Parse/ParsePragma.cpp @@ -1281,8 +1281,8 @@ }; if (Tok.is(tok::l_square) && NextToken().is(tok::l_square)) { - // Parse the CXX11 style attribute. - ParseCXX11AttributeSpecifier(Attrs); + // Parse the C++11 or C2x style attribute. + ParseAttributeSpecifier(Attrs); } else if (Tok.is(tok::kw___attribute)) { ConsumeToken(); if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after, Index: lib/Parse/ParseStmt.cpp =================================================================== --- lib/Parse/ParseStmt.cpp +++ lib/Parse/ParseStmt.cpp @@ -103,7 +103,7 @@ ParenBraceBracketBalancer BalancerRAIIObj(*this); ParsedAttributesWithRange Attrs(AttrFactory); - MaybeParseCXX11Attributes(Attrs, nullptr, /*MightBeObjCMessageSend*/ true); + MaybeParseAttributes(Attrs, nullptr, /*MightBeObjCMessageSend*/ true); if (!MaybeParseOpenCLUnrollHintAttribute(Attrs)) return StmtError(); @@ -1011,8 +1011,8 @@ ConsumeToken(); ParsedAttributesWithRange attrs(AttrFactory); - MaybeParseCXX11Attributes(attrs, nullptr, - /*MightBeObjCMessageSend*/ true); + MaybeParseAttributes(attrs, nullptr, + /*MightBeObjCMessageSend*/ true); // If this is the start of a declaration, parse it as such. if (isDeclarationStatement()) { @@ -1476,7 +1476,7 @@ T.consumeOpen(); // A do-while expression is not a condition, so can't have attributes. - DiagnoseAndSkipCXX11Attributes(); + DiagnoseAndSkipAttributes(); ExprResult Cond = ParseExpression(); T.consumeClose(); @@ -1499,7 +1499,7 @@ if (Next.isOneOf(tok::l_square, tok::kw_alignas)) { TentativeParsingAction PA(*this); ConsumeToken(); - SkipCXX11Attributes(); + SkipAttributes(); bool Result = Tok.is(tok::colon); PA.Revert(); return Result; @@ -1589,7 +1589,7 @@ } ParsedAttributesWithRange attrs(AttrFactory); - MaybeParseCXX11Attributes(attrs); + MaybeParseAttributes(attrs); // Parse the first part of the for specifier. if (Tok.is(tok::semi)) { // for (; @@ -1601,7 +1601,7 @@ ProhibitAttributes(attrs); IdentifierInfo *Name = Tok.getIdentifierInfo(); SourceLocation Loc = ConsumeToken(); - MaybeParseCXX11Attributes(attrs); + MaybeParseAttributes(attrs); ForRangeInit.ColonLoc = ConsumeToken(); if (Tok.is(tok::l_brace)) @@ -1941,7 +1941,7 @@ } // Get the next statement. - MaybeParseCXX11Attributes(Attrs); + MaybeParseAttributes(Attrs); StmtResult S = ParseStatementOrDeclarationAfterAttributes( Stmts, Allowed, TrailingElseLoc, Attrs); @@ -2122,7 +2122,7 @@ // C++11 attributes can't appear here, despite this context seeming // statement-like. - DiagnoseAndSkipCXX11Attributes(); + DiagnoseAndSkipAttributes(); if (Tok.isNot(tok::kw_catch)) return StmtError(Diag(Tok, diag::err_expected_catch)); @@ -2170,7 +2170,7 @@ Decl *ExceptionDecl = nullptr; if (Tok.isNot(tok::ellipsis)) { ParsedAttributesWithRange Attributes(AttrFactory); - MaybeParseCXX11Attributes(Attributes); + MaybeParseAttributes(Attributes); DeclSpec DS(AttrFactory); DS.takeAttributesFrom(Attributes); Index: lib/Parse/ParseTemplate.cpp =================================================================== --- lib/Parse/ParseTemplate.cpp +++ lib/Parse/ParseTemplate.cpp @@ -194,7 +194,7 @@ } ParsedAttributesWithRange prefixAttrs(AttrFactory); - MaybeParseCXX11Attributes(prefixAttrs); + MaybeParseAttributes(prefixAttrs); if (Tok.is(tok::kw_using)) { // FIXME: We should return the DeclGroup to the caller. Index: lib/Parse/ParseTentative.cpp =================================================================== --- lib/Parse/ParseTentative.cpp +++ lib/Parse/ParseTentative.cpp @@ -587,9 +587,9 @@ /// attribute-argument-clause: /// '(' balanced-token-seq ')' Parser::CXX11AttributeKind -Parser::isCXX11AttributeSpecifier(bool Disambiguate, +Parser::isAttributeSpecifier(bool Disambiguate, bool OuterMightBeMessageSend) { - if (Tok.is(tok::kw_alignas)) + if (Tok.is(tok::kw_alignas) && getLangOpts().CPlusPlus11) return CAK_AttributeSpecifier; if (Tok.isNot(tok::l_square) || NextToken().isNot(tok::l_square)) @@ -660,13 +660,13 @@ // requirements of an identifier is contained in an attribute-token, // it is considered an identifier. SourceLocation Loc; - if (!TryParseCXX11AttributeIdentifier(Loc)) { + if (!TryParseAttributeIdentifier(Loc)) { IsAttribute = false; break; } if (Tok.is(tok::coloncolon)) { ConsumeToken(); - if (!TryParseCXX11AttributeIdentifier(Loc)) { + if (!TryParseAttributeIdentifier(Loc)) { IsAttribute = false; break; } @@ -1753,8 +1753,8 @@ } // An attribute-specifier-seq here is a sign of a function declarator. - if (isCXX11AttributeSpecifier(/*Disambiguate*/false, - /*OuterMightBeMessageSend*/true)) + if (isAttributeSpecifier(/*Disambiguate*/ false, + /*OuterMightBeMessageSend*/ true)) return TPResult::True; ParsedAttributes attrs(AttrFactory); Index: lib/Parse/Parser.cpp =================================================================== --- lib/Parse/Parser.cpp +++ lib/Parse/Parser.cpp @@ -608,7 +608,7 @@ } ParsedAttributesWithRange attrs(AttrFactory); - MaybeParseCXX11Attributes(attrs); + MaybeParseAttributes(attrs); Result = ParseExternalDeclaration(attrs); return false; @@ -2028,7 +2028,7 @@ // FIXME: Support module import within __if_exists? while (Tok.isNot(tok::r_brace) && !isEofOrEom()) { ParsedAttributesWithRange attrs(AttrFactory); - MaybeParseCXX11Attributes(attrs); + MaybeParseAttributes(attrs); DeclGroupPtrTy Result = ParseExternalDeclaration(attrs); if (Result && !getCurScope()->getParent()) Actions.getASTConsumer().HandleTopLevelDecl(Result.get()); @@ -2070,8 +2070,8 @@ // We don't support any module attributes yet; just parse them and diagnose. ParsedAttributesWithRange Attrs(AttrFactory); - MaybeParseCXX11Attributes(Attrs); - ProhibitCXX11Attributes(Attrs, diag::err_attribute_not_module_attr); + MaybeParseAttributes(Attrs); + ProhibitAttributes(Attrs, diag::err_attribute_not_module_attr); ExpectAndConsumeSemi(diag::err_module_expected_semi); @@ -2098,9 +2098,9 @@ return nullptr; ParsedAttributesWithRange Attrs(AttrFactory); - MaybeParseCXX11Attributes(Attrs); + MaybeParseAttributes(Attrs); // We don't support any module import attributes yet. - ProhibitCXX11Attributes(Attrs, diag::err_attribute_not_import_attr); + ProhibitAttributes(Attrs, diag::err_attribute_not_import_attr); if (PP.hadModuleLoaderFatalFailure()) { // With a fatal failure in the module loader, we abort parsing. Index: lib/Sema/AttributeList.cpp =================================================================== --- lib/Sema/AttributeList.cpp +++ lib/Sema/AttributeList.cpp @@ -114,7 +114,8 @@ // Normalize the attribute name, __foo__ becomes foo. This is only allowable // for GNU attributes. bool IsGNU = SyntaxUsed == AttributeList::AS_GNU || - (SyntaxUsed == AttributeList::AS_CXX11 && ScopeName == "gnu"); + ((SyntaxUsed == AttributeList::AS_CXX11 || + SyntaxUsed == AttributeList::AS_C2x) && ScopeName == "gnu"); if (IsGNU && AttrName.size() >= 4 && AttrName.startswith("__") && AttrName.endswith("__")) AttrName = AttrName.slice(2, AttrName.size() - 2); @@ -135,7 +136,7 @@ // Ensure that in the case of C++11 attributes, we look for '::foo' if it is // unscoped. - if (ScopeName || SyntaxUsed == AS_CXX11) + if (ScopeName || SyntaxUsed == AS_CXX11 || SyntaxUsed == AS_C2x) FullName += "::"; FullName += AttrName; Index: test/CXX/dcl.dcl/dcl.attr/dcl.align/p6.cpp =================================================================== --- test/CXX/dcl.dcl/dcl.attr/dcl.align/p6.cpp +++ test/CXX/dcl.dcl/dcl.attr/dcl.align/p6.cpp @@ -28,18 +28,18 @@ alignas(4) extern int n9; // expected-note {{declared with 'alignas' attribute here}} -enum alignas(2) E : char; // expected-note {{declared with 'alignas' attribute here}} -enum E : char {}; // expected-error {{'alignas' must be specified on definition if it is specified on any declaration}} +enum alignas(2) E : char; // expected-error {{an attribute list cannot appear here}} +enum E : char {}; -enum alignas(4) F : char; // expected-note {{previous declaration is here}} -enum alignas(2) F : char; // expected-error {{redeclaration has different alignment requirement (2 vs 4)}} +enum alignas(4) F : char; // expected-error {{an attribute list cannot appear here}} +enum alignas(2) F : char; // expected-error {{an attribute list cannot appear here}} enum G : char; enum alignas(8) G : char {}; enum G : char; -enum H : char {}; // expected-error {{'alignas' must be specified on definition if it is specified on any declaration}} -enum alignas(1) H : char; // expected-note {{declared with 'alignas' attribute here}} +enum H : char {}; +enum alignas(1) H : char; // expected-error {{an attribute list cannot appear here}} struct S; @@ -74,7 +74,7 @@ char *x1248 = X<1,2,4,8>::Buffer; // expected-note {{in instantiation of}} template struct Y { - enum alignas(M) alignas(N) E : char; + enum alignas(M) alignas(N) E : char; // expected-error {{an attribute list cannot appear here}} }; template enum alignas(O) alignas(P) Y::E : char { e }; Index: test/Driver/unknown-std.c =================================================================== --- test/Driver/unknown-std.c +++ test/Driver/unknown-std.c @@ -14,6 +14,7 @@ // CHECK-NEXT: note: use 'gnu99' for 'ISO C 1999 with GNU extensions' standard // CHECK-NEXT: note: use 'c11' or 'iso9899:2011' for 'ISO C 2011' standard // CHECK-NEXT: note: use 'gnu11' for 'ISO C 2011 with GNU extensions' standard +// CHECK-NEXT: note: use 'c2x' for 'Working draft for ISO C 202x' standard // Make sure that no other output is present. // CHECK-NOT: {{^.+$}} Index: test/Misc/ast-dump-c-attr.c =================================================================== --- test/Misc/ast-dump-c-attr.c +++ test/Misc/ast-dump-c-attr.c @@ -0,0 +1,46 @@ +// RUN: %clang_cc1 -triple x86_64-pc-linux -std=c2x -fc-attributes -Wno-deprecated-declarations -ast-dump -ast-dump-filter Test %s | FileCheck --strict-whitespace %s + +int Test1 [[deprecated]]; +// CHECK: VarDecl{{.*}}Test1 +// CHECK-NEXT: DeprecatedAttr 0x{{[^ ]*}} "" "" + +enum [[deprecated("Frobble")]] Test2 { + Test3 [[deprecated]] +}; +// CHECK: EnumDecl{{.*}}Test2 +// CHECK-NEXT: DeprecatedAttr 0x{{[^ ]*}} "Frobble" "" +// CHECK-NEXT: EnumConstantDecl{{.*}}Test3 +// CHECK-NEXT: DeprecatedAttr 0x{{[^ ]*}} "" "" + +struct [[deprecated]] Test4 { + [[deprecated("Frobble")]] int Test5, Test6; + int Test7 [[deprecated]] : 12; +}; +// CHECK: RecordDecl{{.*}}Test4 +// CHECK-NEXT: DeprecatedAttr 0x{{[^ ]*}} "" "" +// CHECK-NEXT: FieldDecl{{.*}}Test5 +// CHECK-NEXT: DeprecatedAttr 0x{{[^ ]*}} "Frobble" "" +// CHECK-NEXT: FieldDecl{{.*}}Test6 +// CHECK-NEXT: DeprecatedAttr 0x{{[^ ]*}} "Frobble" "" +// CHECK-NEXT: FieldDecl{{.*}}Test7 +// CHECK-NEXT: IntegerLiteral{{.*}}'int' 12 +// CHECK-NEXT: DeprecatedAttr 0x{{[^ ]*}} "" "" + +struct [[deprecated]] Test8; +// CHECK: RecordDecl{{.*}}Test8 +// CHECK-NEXT: DeprecatedAttr 0x{{[^ ]*}} "" "" + +[[deprecated]] void Test9(int Test10 [[deprecated]]); +// CHECK: FunctionDecl{{.*}}Test9 +// CHECK-NEXT: ParmVarDecl{{.*}}Test10 +// CHECK-NEXT: DeprecatedAttr 0x{{[^ ]*}} "" "" +// CHECK-NEXT: DeprecatedAttr 0x{{[^ ]*}} "" "" + +void Test11 [[deprecated]](void); +// CHECK: FunctionDecl{{.*}}Test11 +// CHECK-NEXT: DeprecatedAttr 0x{{[^ ]*}} "" "" + +void Test12(void) [[deprecated]] {} +// CHECK: FunctionDecl{{.*}}Test12 +// CHECK-NEXT: CompoundStmt +// CHECK-NEXT: DeprecatedAttr 0x{{[^ ]*}} "" "" Index: test/Parser/c2x-attributes.c =================================================================== --- test/Parser/c2x-attributes.c +++ test/Parser/c2x-attributes.c @@ -0,0 +1,106 @@ +// RUN: %clang_cc1 -fsyntax-only -fc-attributes -verify %s -std=c2x + +enum [[]] E { + One [[]], + Two, + Three [[]] +}; + +enum [[]] { Four }; +[[]] enum E2 { Five }; // expected-error {{an attribute list cannot appear here}} + +// FIXME: this diagnostic can be improved. +enum { [[]] Six }; // expected-error {{expected identifier}} + +// FIXME: this diagnostic can be improved. +enum E3 [[]] { Seven }; // expected-error {{expected identifier or '('}} + +struct [[]] S1 { + int i [[]]; + int [[]] j; + int k[10] [[]]; + int l[[]][10]; + [[]] int m, n; + int o [[]] : 12; +}; + +[[]] struct S2 { int a; }; // expected-error {{an attribute list cannot appear here}} +struct S3 [[]] { int a; }; // expected-error {{an attribute list cannot appear here}} + +union [[]] U { + double d [[]]; + [[]] int i; +}; + +[[]] union U2 { double d; }; // expected-error {{an attribute list cannot appear here}} +union U3 [[]] { double d; }; // expected-error {{an attribute list cannot appear here}} + +struct [[]] IncompleteStruct; +union [[]] IncompleteUnion; +enum [[]] IncompleteEnum; // expected-error {{an attribute list cannot appear here}} + +[[]] void f1(void); +void [[]] f2(void); +void f3 [[]] (void); +void f4(void) [[]]; + +void f5(int i [[]], [[]] int j, int [[]] k); + +void f6(a, b) [[]] int a; int b; { // expected-error {{an attribute list cannot appear here}} +} + +// FIXME: technically, an attribute list cannot appear here, but we currently +// parse it as part of the return type of the function, which is reasonable +// behavior given that we *don't* want to parse it as part of the K&R parameter +// declarations. It is disallowed to avoid a parsing ambiguity we already +// handle well. +int (*f7(a, b))(int, int) [[]] int a; int b; { + return 0; +} + +[[]] int a, b; +int c [[]], d [[]]; + +void f8(void) [[]] { + [[]] int i, j; + int k, l [[]]; +} + +[[]] void f9(void) { + int i[10] [[]]; + int (*fp1)(void)[[]]; + int (*fp2 [[]])(void); + + int * [[]] *ipp; +} + +void f10(int j[static 10] [[]], int k[*] [[]]); + +void f11(void) { + [[]] {} + [[]] if (1) {} + + [[]] switch (1) { + [[]] case 1: [[]] break; + [[]] default: break; + } + + goto foo; + [[]] foo: (void)1; + + [[]] for (;;); + [[]] while (1); + [[]] do [[]] { } while(1); + + [[]] (void)1; + + [[]]; + + (void)sizeof(int [4][[]]); + (void)sizeof(struct [[]] S3 { int a [[]]; }); + + [[]] return; +} + +[[attr]] void f12(void); // expected-warning {{unknown attribute 'attr' ignored}} +[[vendor::attr]] void f13(void); // expected-warning {{unknown attribute 'attr' ignored}} Index: test/Parser/cxx0x-attributes.cpp =================================================================== --- test/Parser/cxx0x-attributes.cpp +++ test/Parser/cxx0x-attributes.cpp @@ -175,15 +175,15 @@ template <> struct [[]] Template; enum [[]] E1 {}; -enum [[]] E2; // expected-error {{forbids forward references}} -enum [[]] E1; -enum [[]] E3 : int; +enum [[]] E2; // expected-error {{forbids forward references}} // expected-error {{an attribute list cannot appear here}} +enum [[]] E1; // expected-error {{an attribute list cannot appear here}} +enum [[]] E3 : int; // expected-error {{an attribute list cannot appear here}} enum [[]] { k_123 [[]] = 123 // expected-warning {{attributes on an enumerator declaration are incompatible with C++ standards before C++17}} }; enum [[]] E1 e; // expected-error {{an attribute list cannot appear here}} enum [[]] class E4 { }; // expected-error {{an attribute list cannot appear here}} -enum struct [[]] E5; +enum struct [[]] E5; // expected-error {{an attribute list cannot appear here}} struct S { friend int f [[]] (); // expected-FIXME{{an attribute list cannot appear here}} Index: test/Sema/attr-deprecated-c2x.c =================================================================== --- test/Sema/attr-deprecated-c2x.c +++ test/Sema/attr-deprecated-c2x.c @@ -0,0 +1,54 @@ +// RUN: %clang_cc1 %s -verify -fsyntax-only -std=c2x -fc-attributes + +int f() [[deprecated]]; // expected-note 2 {{'f' has been explicitly marked deprecated here}} +void g() [[deprecated]];// expected-note {{'g' has been explicitly marked deprecated here}} +void g(); + +extern int var [[deprecated]]; // expected-note 2 {{'var' has been explicitly marked deprecated here}} + +int a() { + int (*ptr)() = f; // expected-warning {{'f' is deprecated}} + f(); // expected-warning {{'f' is deprecated}} + + // test if attributes propagate to functions + g(); // expected-warning {{'g' is deprecated}} + + return var; // expected-warning {{'var' is deprecated}} +} + +// test if attributes propagate to variables +extern int var; +int w() { + return var; // expected-warning {{'var' is deprecated}} +} + +int old_fn() [[deprecated]];// expected-note {{'old_fn' has been explicitly marked deprecated here}} +int old_fn(); +int (*fn_ptr)() = old_fn; // expected-warning {{'old_fn' is deprecated}} + +int old_fn() { + return old_fn()+1; // no warning, deprecated functions can use deprecated symbols. +} + +struct foo { + int x [[deprecated]]; // expected-note 3 {{'x' has been explicitly marked deprecated here}} +}; + +void test1(struct foo *F) { + ++F->x; // expected-warning {{'x' is deprecated}} + struct foo f1 = { .x = 17 }; // expected-warning {{'x' is deprecated}} + struct foo f2 = { 17 }; // expected-warning {{'x' is deprecated}} +} + +typedef struct foo foo_dep [[deprecated]]; // expected-note {{'foo_dep' has been explicitly marked deprecated here}} +foo_dep *test2; // expected-warning {{'foo_dep' is deprecated}} + +struct [[deprecated, // expected-note {{'bar_dep' has been explicitly marked deprecated here}} + invalid_attribute]] bar_dep ; // expected-warning {{unknown attribute 'invalid_attribute' ignored}} + +struct bar_dep *test3; // expected-warning {{'bar_dep' is deprecated}} + +[[deprecated("this is the message")]] int i; // expected-note {{'i' has been explicitly marked deprecated here}} +void test4(void) { + i = 12; // expected-warning {{'i' is deprecated: this is the message}} +} Index: test/Sema/c11-compat.c =================================================================== --- test/Sema/c11-compat.c +++ test/Sema/c11-compat.c @@ -0,0 +1,4 @@ +// RUN: %clang_cc1 -fsyntax-only -std=c2x -fc-attributes -Wc11-compat -verify %s + +[[]] int i; // expected-warning {{attribute syntax is incompatible with standards before C2x}} + Index: utils/TableGen/ClangAttrEmitter.cpp =================================================================== --- utils/TableGen/ClangAttrEmitter.cpp +++ utils/TableGen/ClangAttrEmitter.cpp @@ -58,7 +58,7 @@ assert(V != "GCC" && "Given a GCC spelling, which means this hasn't been" "flattened!"); - if (V == "CXX11" || V == "Pragma") + if (V == "CXX11" || V == "C2x" || V == "Pragma") NS = Spelling.getValueAsString("Namespace"); bool Unset; K = Spelling.getValueAsBitOrUnset("KnownToGCC", Unset); @@ -1326,7 +1326,7 @@ if (Variety == "GNU") { Prefix = " __attribute__(("; Suffix = "))"; - } else if (Variety == "CXX11") { + } else if (Variety == "CXX11" || Variety == "C2x") { Prefix = " [["; Suffix = "]]"; std::string Namespace = Spellings[I].nameSpace(); @@ -2716,10 +2716,14 @@ // If this is the C++11 variety, also add in the LangOpts test. if (Variety == "CXX11") Test += " && LangOpts.CPlusPlus11"; + else if (Variety == "C2x") + Test += " && LangOpts.C2x && LangOpts.CAttributes"; } else if (Variety == "CXX11") // C++11 mode should be checked against LangOpts, which is presumed to be // present in the caller. Test = "LangOpts.CPlusPlus11"; + else if (Variety == "C2x") + Test = "LangOpts.C2x && LangOpts.CAttributes"; std::string TestStr = !Test.empty() ? Test + " ? " + llvm::itostr(Version) + " : 0" : "1"; @@ -2740,7 +2744,7 @@ // and declspecs. Then generate a big switch statement for each of them. std::vector Attrs = Records.getAllDerivedDefinitions("Attr"); std::vector Declspec, Microsoft, GNU, Pragma; - std::map> CXX; + std::map> CXX, C2x; // Walk over the list of all attributes, and split them out based on the // spelling variety. @@ -2756,6 +2760,8 @@ Microsoft.push_back(R); else if (Variety == "CXX11") CXX[SI.nameSpace()].push_back(R); + else if (Variety == "C2x") + C2x[SI.nameSpace()].push_back(R); else if (Variety == "Pragma") Pragma.push_back(R); } @@ -2775,20 +2781,25 @@ OS << "case AttrSyntax::Pragma:\n"; OS << " return llvm::StringSwitch(Name)\n"; GenerateHasAttrSpellingStringSwitch(Pragma, OS, "Pragma"); - OS << "case AttrSyntax::CXX: {\n"; - // C++11-style attributes are further split out based on the Scope. - for (auto I = CXX.cbegin(), E = CXX.cend(); I != E; ++I) { - if (I != CXX.begin()) - OS << " else "; - if (I->first.empty()) - OS << "if (!Scope || Scope->getName() == \"\") {\n"; - else - OS << "if (Scope->getName() == \"" << I->first << "\") {\n"; - OS << " return llvm::StringSwitch(Name)\n"; - GenerateHasAttrSpellingStringSwitch(I->second, OS, "CXX11", I->first); - OS << "}"; - } - OS << "\n}\n"; + auto fn = [&OS](const char *Spelling, const char *Variety, + const std::map> &List) { + OS << "case AttrSyntax::" << Variety << ": {\n"; + // C++11-style attributes are further split out based on the Scope. + for (auto I = List.cbegin(), E = List.cend(); I != E; ++I) { + if (I != List.cbegin()) + OS << " else "; + if (I->first.empty()) + OS << "if (!Scope || Scope->getName() == \"\") {\n"; + else + OS << "if (Scope->getName() == \"" << I->first << "\") {\n"; + OS << " return llvm::StringSwitch(Name)\n"; + GenerateHasAttrSpellingStringSwitch(I->second, OS, Spelling, I->first); + OS << "}"; + } + OS << "\n}\n"; + }; + fn("CXX11", "CXX", CXX); + fn("C2x", "C2x", C2x); OS << "}\n"; } @@ -2809,10 +2820,11 @@ << StringSwitch(Spellings[I].variety()) .Case("GNU", 0) .Case("CXX11", 1) - .Case("Declspec", 2) - .Case("Microsoft", 3) - .Case("Keyword", 4) - .Case("Pragma", 5) + .Case("C2x", 2) + .Case("Declspec", 3) + .Case("Microsoft", 4) + .Case("Keyword", 5) + .Case("Pragma", 6) .Default(0) << " && Scope == \"" << Spellings[I].nameSpace() << "\")\n" << " return " << I << ";\n"; @@ -3505,7 +3517,7 @@ std::vector Attrs = Records.getAllDerivedDefinitions("Attr"); std::vector GNU, Declspec, Microsoft, CXX11, - Keywords, Pragma; + Keywords, Pragma, C2x; std::set Seen; for (const auto *A : Attrs) { const Record &Attr = *A; @@ -3543,6 +3555,10 @@ Matches = &CXX11; Spelling += S.nameSpace(); Spelling += "::"; + } else if (Variety == "C2x") { + Matches = &C2x; + Spelling += S.nameSpace(); + Spelling += "::"; } else if (Variety == "GNU") Matches = &GNU; else if (Variety == "Declspec") @@ -3581,6 +3597,8 @@ StringMatcher("Name", Microsoft, OS).Emit(); OS << " } else if (AttributeList::AS_CXX11 == Syntax) {\n"; StringMatcher("Name", CXX11, OS).Emit(); + OS << " } else if (AttributeList::AS_C2x == Syntax) {\n"; + StringMatcher("Name", C2x, OS).Emit(); OS << " } else if (AttributeList::AS_Keyword == Syntax || "; OS << "AttributeList::AS_ContextSensitiveKeyword == Syntax) {\n"; StringMatcher("Name", Keywords, OS).Emit(); @@ -3666,10 +3684,11 @@ enum SpellingKind { GNU = 1 << 0, CXX11 = 1 << 1, - Declspec = 1 << 2, - Microsoft = 1 << 3, - Keyword = 1 << 4, - Pragma = 1 << 5 + C2x = 1 << 2, + Declspec = 1 << 3, + Microsoft = 1 << 4, + Keyword = 1 << 5, + Pragma = 1 << 6 }; static void WriteDocumentation(RecordKeeper &Records, @@ -3716,6 +3735,7 @@ SpellingKind Kind = StringSwitch(I.variety()) .Case("GNU", GNU) .Case("CXX11", CXX11) + .Case("C2x", C2x) .Case("Declspec", Declspec) .Case("Microsoft", Microsoft) .Case("Keyword", Keyword) @@ -3725,7 +3745,7 @@ SupportedSpellings |= Kind; std::string Name; - if (Kind == CXX11 && !I.nameSpace().empty()) + if ((Kind == CXX11 || Kind == C2x) && !I.nameSpace().empty()) Name = I.nameSpace() + "::"; Name += I.name(); @@ -3754,13 +3774,15 @@ // List what spelling syntaxes the attribute supports. OS << ".. csv-table:: Supported Syntaxes\n"; - OS << " :header: \"GNU\", \"C++11\", \"__declspec\", \"Keyword\","; + OS << " :header: \"GNU\", \"C++11\", \"C2x\", \"__declspec\", \"Keyword\","; OS << " \"Pragma\", \"Pragma clang attribute\"\n\n"; OS << " \""; if (SupportedSpellings & GNU) OS << "X"; OS << "\",\""; if (SupportedSpellings & CXX11) OS << "X"; OS << "\",\""; + if (SupportedSpellings & C2x) OS << "X"; + OS << "\",\""; if (SupportedSpellings & Declspec) OS << "X"; OS << "\",\""; if (SupportedSpellings & Keyword) OS << "X";