https://github.com/a-tarasyuk updated https://github.com/llvm/llvm-project/pull/141305
>From 3dca561c73e5fec8528ef5cdf2419393d6b49ba9 Mon Sep 17 00:00:00 2001 From: Oleksandr Tarasiuk <oleksandr.taras...@outlook.com> Date: Sat, 24 May 2025 02:52:24 +0300 Subject: [PATCH] [Clang] add fix-it hints for unknown attributes --- clang/docs/ReleaseNotes.rst | 3 + .../include/clang/Basic/AttributeCommonInfo.h | 50 +++-- .../include/clang/Basic/AttributeScopeInfo.h | 35 ++++ clang/include/clang/Sema/ParsedAttr.h | 184 +++++++++--------- clang/lib/AST/ASTImporter.cpp | 5 +- clang/lib/Basic/Attributes.cpp | 56 ++++-- clang/lib/Parse/ParseDecl.cpp | 92 ++++----- clang/lib/Parse/ParseDeclCXX.cpp | 39 ++-- clang/lib/Parse/ParseExprCXX.cpp | 4 +- clang/lib/Parse/ParseHLSL.cpp | 4 +- clang/lib/Parse/ParseObjc.cpp | 2 +- clang/lib/Parse/ParsePragma.cpp | 2 +- clang/lib/Parse/ParseStmt.cpp | 4 +- clang/lib/Sema/SemaAPINotes.cpp | 7 +- clang/lib/Sema/SemaDeclAttr.cpp | 58 ++++-- clang/lib/Sema/SemaDeclCXX.cpp | 3 +- clang/lib/Sema/SemaStmtAttr.cpp | 14 +- clang/lib/Sema/SemaType.cpp | 10 +- clang/lib/Serialization/ASTReaderDecl.cpp | 4 +- .../dcl.module/dcl.module.import/p1.cppm | 2 +- clang/test/FixIt/fixit-unknown-attributes.cpp | 60 ++++++ .../Parser/cxx11-base-spec-attributes.cpp | 2 +- clang/test/Parser/objcxx11-attributes.mm | 2 +- clang/test/Sema/unknown-attributes.c | 11 +- ...attr-non-x86-no_caller_saved_registers.cpp | 2 +- 25 files changed, 408 insertions(+), 247 deletions(-) create mode 100644 clang/include/clang/Basic/AttributeScopeInfo.h create mode 100644 clang/test/FixIt/fixit-unknown-attributes.cpp diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index b93fa33acc2a0..02cca0bb357f9 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -592,6 +592,9 @@ Improvements to Clang's diagnostics trigger a ``'Blue' is deprecated`` warning, which can be turned off with ``-Wno-deprecated-switch-case``. +- Clang now emits fix-it hints for unknown attributes when a spelling + correction is suggested. + Improvements to Clang's time-trace ---------------------------------- diff --git a/clang/include/clang/Basic/AttributeCommonInfo.h b/clang/include/clang/Basic/AttributeCommonInfo.h index b4b8345b4ed40..7581a7a14ea05 100644 --- a/clang/include/clang/Basic/AttributeCommonInfo.h +++ b/clang/include/clang/Basic/AttributeCommonInfo.h @@ -14,6 +14,7 @@ #ifndef LLVM_CLANG_BASIC_ATTRIBUTECOMMONINFO_H #define LLVM_CLANG_BASIC_ATTRIBUTECOMMONINFO_H +#include "clang/Basic/AttributeScopeInfo.h" #include "clang/Basic/SourceLocation.h" #include "clang/Basic/TokenKinds.h" @@ -61,6 +62,7 @@ class AttributeCommonInfo { /// implicitly. AS_Implicit }; + enum Kind { #define PARSED_ATTR(NAME) AT_##NAME, #include "clang/Basic/AttrParsedAttrList.inc" @@ -78,9 +80,9 @@ class AttributeCommonInfo { private: const IdentifierInfo *AttrName = nullptr; - const IdentifierInfo *ScopeName = nullptr; + AttributeScopeInfo AttrScope; SourceRange AttrRange; - const SourceLocation ScopeLoc; + // Corresponds to the Kind enum. LLVM_PREFERRED_TYPE(Kind) unsigned AttrKind : 16; @@ -146,11 +148,10 @@ class AttributeCommonInfo { }; AttributeCommonInfo(const IdentifierInfo *AttrName, - const IdentifierInfo *ScopeName, SourceRange AttrRange, - SourceLocation ScopeLoc, Kind AttrKind, Form FormUsed) - : AttrName(AttrName), ScopeName(ScopeName), AttrRange(AttrRange), - ScopeLoc(ScopeLoc), AttrKind(AttrKind), - SyntaxUsed(FormUsed.getSyntax()), + AttributeScopeInfo AttrScope, SourceRange AttrRange, + Kind AttrKind, Form FormUsed) + : AttrName(AttrName), AttrScope(AttrScope), AttrRange(AttrRange), + AttrKind(AttrKind), SyntaxUsed(FormUsed.getSyntax()), SpellingIndex(FormUsed.getSpellingIndex()), IsAlignas(FormUsed.isAlignas()), IsRegularKeywordAttribute(FormUsed.isRegularKeywordAttribute()) { @@ -158,21 +159,20 @@ class AttributeCommonInfo { "Invalid syntax!"); } - AttributeCommonInfo(const IdentifierInfo *AttrName, - const IdentifierInfo *ScopeName, SourceRange AttrRange, - SourceLocation ScopeLoc, Form FormUsed) + AttributeCommonInfo(const IdentifierInfo *AttrName, AttributeScopeInfo Scope, + SourceRange AttrRange, Form FormUsed) : AttributeCommonInfo( - AttrName, ScopeName, AttrRange, ScopeLoc, - getParsedKind(AttrName, ScopeName, FormUsed.getSyntax()), + AttrName, Scope, AttrRange, + getParsedKind(AttrName, Scope.getName(), FormUsed.getSyntax()), FormUsed) {} AttributeCommonInfo(const IdentifierInfo *AttrName, SourceRange AttrRange, Form FormUsed) - : AttributeCommonInfo(AttrName, nullptr, AttrRange, SourceLocation(), + : AttributeCommonInfo(AttrName, AttributeScopeInfo(), AttrRange, FormUsed) {} AttributeCommonInfo(SourceRange AttrRange, Kind K, Form FormUsed) - : AttributeCommonInfo(nullptr, nullptr, AttrRange, SourceLocation(), K, + : AttributeCommonInfo(nullptr, AttributeScopeInfo(), AttrRange, K, FormUsed) {} AttributeCommonInfo(AttributeCommonInfo &&) = default; @@ -190,17 +190,27 @@ class AttributeCommonInfo { SourceRange getRange() const { return AttrRange; } void setRange(SourceRange R) { AttrRange = R; } - bool hasScope() const { return ScopeName; } - const IdentifierInfo *getScopeName() const { return ScopeName; } - SourceLocation getScopeLoc() const { return ScopeLoc; } + bool hasScope() const { return AttrScope.isValid(); } + bool isExplicitScope() const { return AttrScope.IsExplicit(); } + + const IdentifierInfo *getScopeName() const { return AttrScope.getName(); } + SourceLocation getScopeLoc() const { return AttrScope.getNameLoc(); } /// Gets the normalized full name, which consists of both scope and name and /// with surrounding underscores removed as appropriate (e.g. /// __gnu__::__attr__ will be normalized to gnu::attr). std::string getNormalizedFullName() const; - std::optional<std::string> - getCorrectedFullName(const TargetInfo &Target, - const LangOptions &LangOpts) const; + std::string getNormalizedFullName(StringRef ScopeName, + StringRef AttrName) const; + StringRef getNormalizedScopeName() const; + StringRef getNormalizedAttrName(StringRef ScopeName) const; + + std::optional<StringRef> tryGetCorrectedScopeName(StringRef ScopeName) const; + std::optional<StringRef> + tryGetCorrectedAttrName(StringRef ScopeName, StringRef AttrName, + const TargetInfo &Target, + const LangOptions &LangOpts) const; + SourceRange getNormalizedRange() const; bool isDeclspecAttribute() const { return SyntaxUsed == AS_Declspec; } diff --git a/clang/include/clang/Basic/AttributeScopeInfo.h b/clang/include/clang/Basic/AttributeScopeInfo.h new file mode 100644 index 0000000000000..f86cb714f2be7 --- /dev/null +++ b/clang/include/clang/Basic/AttributeScopeInfo.h @@ -0,0 +1,35 @@ +#ifndef LLVM_CLANG_BASIC_ATTRIBUTESCOPEINFO_H +#define LLVM_CLANG_BASIC_ATTRIBUTESCOPEINFO_H + +#include "clang/Basic/SourceLocation.h" + +namespace clang { + +class IdentifierInfo; + +class AttributeScopeInfo { +public: + AttributeScopeInfo() = default; + + AttributeScopeInfo(const IdentifierInfo *Name, SourceLocation NameLoc) + : Name(Name), NameLoc(NameLoc) {} + + AttributeScopeInfo(const IdentifierInfo *Name, SourceLocation NameLoc, + SourceLocation UsingPrefixLoc) + : Name(Name), NameLoc(NameLoc), UsingPrefixLoc(UsingPrefixLoc) {} + + const IdentifierInfo *getName() const { return Name; } + SourceLocation getNameLoc() const { return NameLoc; } + + bool isValid() const { return Name != nullptr; } + bool IsExplicit() const { return UsingPrefixLoc.isInvalid(); } + +private: + const IdentifierInfo *Name = nullptr; + SourceLocation NameLoc; + SourceLocation UsingPrefixLoc; +}; + +} // namespace clang + +#endif // LLVM_CLANG_BASIC_ATTRIBUTESCOPEINFO_H diff --git a/clang/include/clang/Sema/ParsedAttr.h b/clang/include/clang/Sema/ParsedAttr.h index 428d3111de80d..451997156ec90 100644 --- a/clang/include/clang/Sema/ParsedAttr.h +++ b/clang/include/clang/Sema/ParsedAttr.h @@ -207,10 +207,9 @@ class ParsedAttr final /// Constructor for attributes with expression arguments. ParsedAttr(IdentifierInfo *attrName, SourceRange attrRange, - IdentifierInfo *scopeName, SourceLocation scopeLoc, - ArgsUnion *args, unsigned numArgs, Form formUsed, - SourceLocation ellipsisLoc) - : AttributeCommonInfo(attrName, scopeName, attrRange, scopeLoc, formUsed), + AttributeScopeInfo scope, ArgsUnion *args, unsigned numArgs, + Form formUsed, SourceLocation ellipsisLoc) + : AttributeCommonInfo(attrName, scope, attrRange, formUsed), EllipsisLoc(ellipsisLoc), NumArgs(numArgs), Invalid(false), UsedAsTypeAttr(false), IsAvailability(false), IsTypeTagForDatatype(false), IsProperty(false), HasParsedType(false), @@ -222,14 +221,14 @@ class ParsedAttr final /// Constructor for availability attributes. ParsedAttr(IdentifierInfo *attrName, SourceRange attrRange, - IdentifierInfo *scopeName, SourceLocation scopeLoc, - IdentifierLoc *Parm, const AvailabilityChange &introduced, + AttributeScopeInfo scope, IdentifierLoc *Parm, + const AvailabilityChange &introduced, const AvailabilityChange &deprecated, const AvailabilityChange &obsoleted, SourceLocation unavailable, const Expr *messageExpr, Form formUsed, SourceLocation strict, const Expr *replacementExpr, const IdentifierLoc *environmentLoc) - : AttributeCommonInfo(attrName, scopeName, attrRange, scopeLoc, formUsed), - NumArgs(1), Invalid(false), UsedAsTypeAttr(false), IsAvailability(true), + : AttributeCommonInfo(attrName, scope, attrRange, formUsed), NumArgs(1), + Invalid(false), UsedAsTypeAttr(false), IsAvailability(true), IsTypeTagForDatatype(false), IsProperty(false), HasParsedType(false), HasProcessingCache(false), IsPragmaClangAttribute(false), UnavailableLoc(unavailable), MessageExpr(messageExpr), @@ -243,14 +242,13 @@ class ParsedAttr final /// Constructor for objc_bridge_related attributes. ParsedAttr(IdentifierInfo *attrName, SourceRange attrRange, - IdentifierInfo *scopeName, SourceLocation scopeLoc, - IdentifierLoc *Parm1, IdentifierLoc *Parm2, IdentifierLoc *Parm3, - Form formUsed) - : AttributeCommonInfo(attrName, scopeName, attrRange, scopeLoc, formUsed), - NumArgs(3), Invalid(false), UsedAsTypeAttr(false), - IsAvailability(false), IsTypeTagForDatatype(false), IsProperty(false), - HasParsedType(false), HasProcessingCache(false), - IsPragmaClangAttribute(false), Info(ParsedAttrInfo::get(*this)) { + AttributeScopeInfo scope, IdentifierLoc *Parm1, + IdentifierLoc *Parm2, IdentifierLoc *Parm3, Form formUsed) + : AttributeCommonInfo(attrName, scope, attrRange, formUsed), NumArgs(3), + Invalid(false), UsedAsTypeAttr(false), IsAvailability(false), + IsTypeTagForDatatype(false), IsProperty(false), HasParsedType(false), + HasProcessingCache(false), IsPragmaClangAttribute(false), + Info(ParsedAttrInfo::get(*this)) { ArgsUnion *Args = getArgsBuffer(); Args[0] = Parm1; Args[1] = Parm2; @@ -259,14 +257,14 @@ class ParsedAttr final /// Constructor for type_tag_for_datatype attribute. ParsedAttr(IdentifierInfo *attrName, SourceRange attrRange, - IdentifierInfo *scopeName, SourceLocation scopeLoc, - IdentifierLoc *ArgKind, ParsedType matchingCType, - bool layoutCompatible, bool mustBeNull, Form formUsed) - : AttributeCommonInfo(attrName, scopeName, attrRange, scopeLoc, formUsed), - NumArgs(1), Invalid(false), UsedAsTypeAttr(false), - IsAvailability(false), IsTypeTagForDatatype(true), IsProperty(false), - HasParsedType(false), HasProcessingCache(false), - IsPragmaClangAttribute(false), Info(ParsedAttrInfo::get(*this)) { + AttributeScopeInfo scope, IdentifierLoc *ArgKind, + ParsedType matchingCType, bool layoutCompatible, bool mustBeNull, + Form formUsed) + : AttributeCommonInfo(attrName, scope, attrRange, formUsed), NumArgs(1), + Invalid(false), UsedAsTypeAttr(false), IsAvailability(false), + IsTypeTagForDatatype(true), IsProperty(false), HasParsedType(false), + HasProcessingCache(false), IsPragmaClangAttribute(false), + Info(ParsedAttrInfo::get(*this)) { ArgsUnion PVal(ArgKind); memcpy(getArgsBuffer(), &PVal, sizeof(ArgsUnion)); detail::TypeTagForDatatypeData &ExtraData = getTypeTagForDatatypeDataSlot(); @@ -277,9 +275,9 @@ class ParsedAttr final /// Constructor for attributes with a single type argument. ParsedAttr(IdentifierInfo *attrName, SourceRange attrRange, - IdentifierInfo *scopeName, SourceLocation scopeLoc, - ParsedType typeArg, Form formUsed, SourceLocation ellipsisLoc) - : AttributeCommonInfo(attrName, scopeName, attrRange, scopeLoc, formUsed), + AttributeScopeInfo scope, ParsedType typeArg, Form formUsed, + SourceLocation ellipsisLoc) + : AttributeCommonInfo(attrName, scope, attrRange, formUsed), EllipsisLoc(ellipsisLoc), NumArgs(0), Invalid(false), UsedAsTypeAttr(false), IsAvailability(false), IsTypeTagForDatatype(false), IsProperty(false), HasParsedType(true), @@ -290,13 +288,13 @@ class ParsedAttr final /// Constructor for microsoft __declspec(property) attribute. ParsedAttr(IdentifierInfo *attrName, SourceRange attrRange, - IdentifierInfo *scopeName, SourceLocation scopeLoc, - IdentifierInfo *getterId, IdentifierInfo *setterId, Form formUsed) - : AttributeCommonInfo(attrName, scopeName, attrRange, scopeLoc, formUsed), - NumArgs(0), Invalid(false), UsedAsTypeAttr(false), - IsAvailability(false), IsTypeTagForDatatype(false), IsProperty(true), - HasParsedType(false), HasProcessingCache(false), - IsPragmaClangAttribute(false), Info(ParsedAttrInfo::get(*this)) { + AttributeScopeInfo scope, IdentifierInfo *getterId, + IdentifierInfo *setterId, Form formUsed) + : AttributeCommonInfo(attrName, scope, attrRange, formUsed), NumArgs(0), + Invalid(false), UsedAsTypeAttr(false), IsAvailability(false), + IsTypeTagForDatatype(false), IsProperty(true), HasParsedType(false), + HasProcessingCache(false), IsPragmaClangAttribute(false), + Info(ParsedAttrInfo::get(*this)) { new (&getPropertyDataBuffer()) detail::PropertyData(getterId, setterId); } @@ -738,21 +736,21 @@ class AttributePool { void takeFrom(ParsedAttributesView &List, AttributePool &Pool); ParsedAttr *create(IdentifierInfo *attrName, SourceRange attrRange, - IdentifierInfo *scopeName, SourceLocation scopeLoc, - ArgsUnion *args, unsigned numArgs, ParsedAttr::Form form, + AttributeScopeInfo scope, ArgsUnion *args, + unsigned numArgs, ParsedAttr::Form form, SourceLocation ellipsisLoc = SourceLocation()) { void *memory = allocate( ParsedAttr::totalSizeToAlloc<ArgsUnion, detail::AvailabilityData, detail::TypeTagForDatatypeData, ParsedType, detail::PropertyData>(numArgs, 0, 0, 0, 0)); - return add(new (memory) ParsedAttr(attrName, attrRange, scopeName, scopeLoc, - args, numArgs, form, ellipsisLoc)); + return add(new (memory) ParsedAttr(attrName, attrRange, scope, args, + numArgs, form, ellipsisLoc)); } ParsedAttr *create(IdentifierInfo *attrName, SourceRange attrRange, - IdentifierInfo *scopeName, SourceLocation scopeLoc, - IdentifierLoc *Param, const AvailabilityChange &introduced, + AttributeScopeInfo scope, IdentifierLoc *Param, + const AvailabilityChange &introduced, const AvailabilityChange &deprecated, const AvailabilityChange &obsoleted, SourceLocation unavailable, const Expr *MessageExpr, @@ -760,58 +758,54 @@ class AttributePool { const Expr *ReplacementExpr, IdentifierLoc *EnvironmentLoc) { void *memory = allocate(AttributeFactory::AvailabilityAllocSize); - return add(new (memory) ParsedAttr(attrName, attrRange, scopeName, scopeLoc, - Param, introduced, deprecated, obsoleted, - unavailable, MessageExpr, form, strict, - ReplacementExpr, EnvironmentLoc)); + return add(new (memory) + ParsedAttr(attrName, attrRange, scope, Param, introduced, + deprecated, obsoleted, unavailable, MessageExpr, + form, strict, ReplacementExpr, EnvironmentLoc)); } ParsedAttr *create(IdentifierInfo *attrName, SourceRange attrRange, - IdentifierInfo *scopeName, SourceLocation scopeLoc, - IdentifierLoc *Param1, IdentifierLoc *Param2, - IdentifierLoc *Param3, ParsedAttr::Form form) { + AttributeScopeInfo scope, IdentifierLoc *Param1, + IdentifierLoc *Param2, IdentifierLoc *Param3, + ParsedAttr::Form form) { void *memory = allocate( ParsedAttr::totalSizeToAlloc<ArgsUnion, detail::AvailabilityData, detail::TypeTagForDatatypeData, ParsedType, detail::PropertyData>(3, 0, 0, 0, 0)); - return add(new (memory) ParsedAttr(attrName, attrRange, scopeName, scopeLoc, - Param1, Param2, Param3, form)); + return add(new (memory) ParsedAttr(attrName, attrRange, scope, Param1, + Param2, Param3, form)); } - ParsedAttr * - createTypeTagForDatatype(IdentifierInfo *attrName, SourceRange attrRange, - IdentifierInfo *scopeName, SourceLocation scopeLoc, - IdentifierLoc *argumentKind, - ParsedType matchingCType, bool layoutCompatible, - bool mustBeNull, ParsedAttr::Form form) { + ParsedAttr *createTypeTagForDatatype( + IdentifierInfo *attrName, SourceRange attrRange, AttributeScopeInfo scope, + IdentifierLoc *argumentKind, ParsedType matchingCType, + bool layoutCompatible, bool mustBeNull, ParsedAttr::Form form) { void *memory = allocate(AttributeFactory::TypeTagForDatatypeAllocSize); - return add(new (memory) ParsedAttr(attrName, attrRange, scopeName, scopeLoc, - argumentKind, matchingCType, - layoutCompatible, mustBeNull, form)); + return add(new (memory) ParsedAttr(attrName, attrRange, scope, argumentKind, + matchingCType, layoutCompatible, + mustBeNull, form)); } ParsedAttr *createTypeAttribute(IdentifierInfo *attrName, SourceRange attrRange, - IdentifierInfo *scopeName, - SourceLocation scopeLoc, ParsedType typeArg, + AttributeScopeInfo scope, ParsedType typeArg, ParsedAttr::Form formUsed, SourceLocation ellipsisLoc) { void *memory = allocate( ParsedAttr::totalSizeToAlloc<ArgsUnion, detail::AvailabilityData, detail::TypeTagForDatatypeData, ParsedType, detail::PropertyData>(0, 0, 0, 1, 0)); - return add(new (memory) ParsedAttr(attrName, attrRange, scopeName, scopeLoc, - typeArg, formUsed, ellipsisLoc)); + return add(new (memory) ParsedAttr(attrName, attrRange, scope, typeArg, + formUsed, ellipsisLoc)); } ParsedAttr * createPropertyAttribute(IdentifierInfo *attrName, SourceRange attrRange, - IdentifierInfo *scopeName, SourceLocation scopeLoc, - IdentifierInfo *getterId, IdentifierInfo *setterId, - ParsedAttr::Form formUsed) { + AttributeScopeInfo scope, IdentifierInfo *getterId, + IdentifierInfo *setterId, ParsedAttr::Form formUsed) { void *memory = allocate(AttributeFactory::PropertyAllocSize); - return add(new (memory) ParsedAttr(attrName, attrRange, scopeName, scopeLoc, - getterId, setterId, formUsed)); + return add(new (memory) ParsedAttr(attrName, attrRange, scope, getterId, + setterId, formUsed)); } }; @@ -985,19 +979,19 @@ class ParsedAttributes : public ParsedAttributesView { /// Add attribute with expression arguments. ParsedAttr *addNew(IdentifierInfo *attrName, SourceRange attrRange, - IdentifierInfo *scopeName, SourceLocation scopeLoc, - ArgsUnion *args, unsigned numArgs, ParsedAttr::Form form, + AttributeScopeInfo scope, ArgsUnion *args, + unsigned numArgs, ParsedAttr::Form form, SourceLocation ellipsisLoc = SourceLocation()) { - ParsedAttr *attr = pool.create(attrName, attrRange, scopeName, scopeLoc, - args, numArgs, form, ellipsisLoc); + ParsedAttr *attr = pool.create(attrName, attrRange, scope, args, numArgs, + form, ellipsisLoc); addAtEnd(attr); return attr; } /// Add availability attribute. ParsedAttr *addNew(IdentifierInfo *attrName, SourceRange attrRange, - IdentifierInfo *scopeName, SourceLocation scopeLoc, - IdentifierLoc *Param, const AvailabilityChange &introduced, + AttributeScopeInfo scope, IdentifierLoc *Param, + const AvailabilityChange &introduced, const AvailabilityChange &deprecated, const AvailabilityChange &obsoleted, SourceLocation unavailable, const Expr *MessageExpr, @@ -1005,33 +999,31 @@ class ParsedAttributes : public ParsedAttributesView { const Expr *ReplacementExpr, IdentifierLoc *EnvironmentLoc) { ParsedAttr *attr = - pool.create(attrName, attrRange, scopeName, scopeLoc, Param, introduced, - deprecated, obsoleted, unavailable, MessageExpr, form, - strict, ReplacementExpr, EnvironmentLoc); + pool.create(attrName, attrRange, scope, Param, introduced, deprecated, + obsoleted, unavailable, MessageExpr, form, strict, + ReplacementExpr, EnvironmentLoc); addAtEnd(attr); return attr; } /// Add objc_bridge_related attribute. ParsedAttr *addNew(IdentifierInfo *attrName, SourceRange attrRange, - IdentifierInfo *scopeName, SourceLocation scopeLoc, - IdentifierLoc *Param1, IdentifierLoc *Param2, - IdentifierLoc *Param3, ParsedAttr::Form form) { - ParsedAttr *attr = pool.create(attrName, attrRange, scopeName, scopeLoc, - Param1, Param2, Param3, form); + AttributeScopeInfo scope, IdentifierLoc *Param1, + IdentifierLoc *Param2, IdentifierLoc *Param3, + ParsedAttr::Form form) { + ParsedAttr *attr = + pool.create(attrName, attrRange, scope, Param1, Param2, Param3, form); addAtEnd(attr); return attr; } /// Add type_tag_for_datatype attribute. - ParsedAttr * - addNewTypeTagForDatatype(IdentifierInfo *attrName, SourceRange attrRange, - IdentifierInfo *scopeName, SourceLocation scopeLoc, - IdentifierLoc *argumentKind, - ParsedType matchingCType, bool layoutCompatible, - bool mustBeNull, ParsedAttr::Form form) { + ParsedAttr *addNewTypeTagForDatatype( + IdentifierInfo *attrName, SourceRange attrRange, AttributeScopeInfo scope, + IdentifierLoc *argumentKind, ParsedType matchingCType, + bool layoutCompatible, bool mustBeNull, ParsedAttr::Form form) { ParsedAttr *attr = pool.createTypeTagForDatatype( - attrName, attrRange, scopeName, scopeLoc, argumentKind, matchingCType, + attrName, attrRange, scope, argumentKind, matchingCType, layoutCompatible, mustBeNull, form); addAtEnd(attr); return attr; @@ -1039,12 +1031,11 @@ class ParsedAttributes : public ParsedAttributesView { /// Add an attribute with a single type argument. ParsedAttr *addNewTypeAttr(IdentifierInfo *attrName, SourceRange attrRange, - IdentifierInfo *scopeName, SourceLocation scopeLoc, - ParsedType typeArg, ParsedAttr::Form formUsed, + AttributeScopeInfo scope, ParsedType typeArg, + ParsedAttr::Form formUsed, SourceLocation ellipsisLoc = SourceLocation()) { - ParsedAttr *attr = - pool.createTypeAttribute(attrName, attrRange, scopeName, scopeLoc, - typeArg, formUsed, ellipsisLoc); + ParsedAttr *attr = pool.createTypeAttribute(attrName, attrRange, scope, + typeArg, formUsed, ellipsisLoc); addAtEnd(attr); return attr; } @@ -1052,11 +1043,10 @@ class ParsedAttributes : public ParsedAttributesView { /// Add microsoft __delspec(property) attribute. ParsedAttr * addNewPropertyAttr(IdentifierInfo *attrName, SourceRange attrRange, - IdentifierInfo *scopeName, SourceLocation scopeLoc, - IdentifierInfo *getterId, IdentifierInfo *setterId, - ParsedAttr::Form formUsed) { + AttributeScopeInfo scope, IdentifierInfo *getterId, + IdentifierInfo *setterId, ParsedAttr::Form formUsed) { ParsedAttr *attr = pool.createPropertyAttribute( - attrName, attrRange, scopeName, scopeLoc, getterId, setterId, formUsed); + attrName, attrRange, scope, getterId, setterId, formUsed); addAtEnd(attr); return attr; } diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index b481ad5df667e..6847728eb9d9f 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -9296,8 +9296,9 @@ class AttrImporter { if (Err) return; - AttributeCommonInfo ToI(ToAttrName, ToScopeName, ToAttrRange, ToScopeLoc, - FromAttr->getParsedKind(), FromAttr->getForm()); + AttributeCommonInfo ToI( + ToAttrName, AttributeScopeInfo(ToScopeName, ToScopeLoc), ToAttrRange, + FromAttr->getParsedKind(), FromAttr->getForm()); // The "SemanticSpelling" is not needed to be passed to the constructor. // That value is recalculated from the SpellingListIndex if needed. ToAttr = T::Create(Importer.getToContext(), diff --git a/clang/lib/Basic/Attributes.cpp b/clang/lib/Basic/Attributes.cpp index ebc86a5adf7a7..ce409d7b7bc99 100644 --- a/clang/lib/Basic/Attributes.cpp +++ b/clang/lib/Basic/Attributes.cpp @@ -120,7 +120,6 @@ normalizeAttrScopeName(const IdentifierInfo *ScopeName, AttributeCommonInfo::Syntax SyntaxUsed) { if (ScopeName) return normalizeAttrScopeName(ScopeName->getName(), SyntaxUsed); - return ""; } @@ -142,12 +141,24 @@ static StringRef normalizeAttrName(StringRef AttrName, return AttrName; } +StringRef AttributeCommonInfo::getNormalizedScopeName() const { + return normalizeAttrScopeName(getScopeName(), getSyntax()); +} + +StringRef +AttributeCommonInfo::getNormalizedAttrName(StringRef ScopeName) const { + return normalizeAttrName(getAttrName()->getName(), ScopeName, getSyntax()); + ; +} + bool AttributeCommonInfo::isGNUScope() const { - return ScopeName && (ScopeName->isStr("gnu") || ScopeName->isStr("__gnu__")); + return AttrScope.isValid() && (AttrScope.getName()->isStr("gnu") || + AttrScope.getName()->isStr("__gnu__")); } bool AttributeCommonInfo::isClangScope() const { - return ScopeName && (ScopeName->isStr("clang") || ScopeName->isStr("_Clang")); + return AttrScope.isValid() && (AttrScope.getName()->isStr("clang") || + AttrScope.getName()->isStr("_Clang")); } #include "clang/Sema/AttrParsedAttrKinds.inc" @@ -199,8 +210,16 @@ std::string AttributeCommonInfo::getNormalizedFullName() const { normalizeName(getAttrName(), getScopeName(), getSyntax())); } +std::string +AttributeCommonInfo::getNormalizedFullName(StringRef ScopeName, + StringRef AttrName) const { + return static_cast<std::string>( + normalizeName(AttrName, ScopeName, getSyntax())); +} + SourceRange AttributeCommonInfo::getNormalizedRange() const { - return hasScope() ? SourceRange(ScopeLoc, AttrRange.getEnd()) : AttrRange; + return hasScope() ? SourceRange(AttrScope.getNameLoc(), AttrRange.getEnd()) + : AttrRange; } static AttributeCommonInfo::Scope @@ -239,10 +258,8 @@ static constexpr const char *AttrScopeSpellingList[] = { #include "clang/Basic/AttributeSpellingList.inc" }; -std::optional<std::string> -AttributeCommonInfo::getCorrectedFullName(const TargetInfo &Target, - const LangOptions &LangOpts) const { - StringRef ScopeName = normalizeAttrScopeName(getScopeName(), getSyntax()); +std::optional<StringRef> +AttributeCommonInfo::tryGetCorrectedScopeName(StringRef ScopeName) const { if (ScopeName.size() > 0 && llvm::none_of(AttrScopeSpellingList, [&](const char *S) { return S == ScopeName; })) { @@ -251,25 +268,26 @@ AttributeCommonInfo::getCorrectedFullName(const TargetInfo &Target, STC.add(Scope); if (auto CorrectedScopeName = STC.getCorrection()) - ScopeName = *CorrectedScopeName; + return CorrectedScopeName; } + return std::nullopt; +} - StringRef AttrName = - normalizeAttrName(getAttrName()->getName(), ScopeName, getSyntax()); +std::optional<StringRef> AttributeCommonInfo::tryGetCorrectedAttrName( + StringRef ScopeName, StringRef AttrName, const TargetInfo &Target, + const LangOptions &LangOpts) const { if (llvm::none_of(AttrSpellingList, [&](const char *A) { return A == AttrName; })) { SimpleTypoCorrection STC(AttrName); for (const auto &Attr : AttrSpellingList) STC.add(Attr); - if (auto CorrectedAttrName = STC.getCorrection()) - AttrName = *CorrectedAttrName; + if (auto CorrectedAttrName = STC.getCorrection()) { + if (hasAttribute(getSyntax(), ScopeName, *CorrectedAttrName, Target, + LangOpts, + /*CheckPlugins=*/true)) + return CorrectedAttrName; + } } - - if (hasAttribute(getSyntax(), ScopeName, AttrName, Target, LangOpts, - /*CheckPlugins=*/true)) - return static_cast<std::string>( - normalizeName(AttrName, ScopeName, getSyntax())); - return std::nullopt; } diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 7a87cd2e340cc..94d3a94defb80 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -154,7 +154,7 @@ bool Parser::ParseSingleGNUAttribute(ParsedAttributes &Attrs, SourceLocation AttrNameLoc = ConsumeToken(); if (Tok.isNot(tok::l_paren)) { - Attrs.addNew(AttrName, AttrNameLoc, nullptr, AttrNameLoc, nullptr, 0, + Attrs.addNew(AttrName, AttrNameLoc, AttributeScopeInfo(), nullptr, 0, ParsedAttr::Form::GNU()); return false; } @@ -399,12 +399,12 @@ void Parser::ParseAttributeWithTypeArg(IdentifierInfo &AttrName, return; if (T.isUsable()) - Attrs.addNewTypeAttr(&AttrName, - SourceRange(AttrNameLoc, Parens.getCloseLocation()), - ScopeName, ScopeLoc, T.get(), Form); + Attrs.addNewTypeAttr( + &AttrName, SourceRange(AttrNameLoc, Parens.getCloseLocation()), + AttributeScopeInfo(ScopeName, ScopeLoc), T.get(), Form); else Attrs.addNew(&AttrName, SourceRange(AttrNameLoc, Parens.getCloseLocation()), - ScopeName, ScopeLoc, nullptr, 0, Form); + AttributeScopeInfo(ScopeName, ScopeLoc), nullptr, 0, Form); } ExprResult @@ -624,10 +624,12 @@ unsigned Parser::ParseAttributeArgsCommon( if (AttributeIsTypeArgAttr && !TheParsedType.get().isNull()) { Attrs.addNewTypeAttr(AttrName, SourceRange(AttrNameLoc, RParen), - ScopeName, ScopeLoc, TheParsedType, Form); + AttributeScopeInfo(ScopeName, ScopeLoc), + TheParsedType, Form); } else { - Attrs.addNew(AttrName, SourceRange(AttrLoc, RParen), ScopeName, ScopeLoc, - ArgExprs.data(), ArgExprs.size(), Form); + Attrs.addNew(AttrName, SourceRange(AttrLoc, RParen), + AttributeScopeInfo(ScopeName, ScopeLoc), ArgExprs.data(), + ArgExprs.size(), Form); } } @@ -867,7 +869,7 @@ bool Parser::ParseMicrosoftDeclSpecArgs(IdentifierInfo *AttrName, // Only add the property attribute if it was well-formed. if (!HasInvalidAccessor) - Attrs.addNewPropertyAttr(AttrName, AttrNameLoc, nullptr, SourceLocation(), + Attrs.addNewPropertyAttr(AttrName, AttrNameLoc, AttributeScopeInfo(), AccessorNames[AK_Get], AccessorNames[AK_Put], ParsedAttr::Form::Declspec()); T.skipToEnd(); @@ -953,7 +955,7 @@ void Parser::ParseMicrosoftDeclSpecs(ParsedAttributes &Attrs) { << AttrName->getName(); if (!AttrHandled) - Attrs.addNew(AttrName, AttrNameLoc, nullptr, AttrNameLoc, nullptr, 0, + Attrs.addNew(AttrName, AttrNameLoc, AttributeScopeInfo(), nullptr, 0, ParsedAttr::Form::Declspec()); } T.consumeClose(); @@ -981,7 +983,7 @@ void Parser::ParseMicrosoftTypeAttributes(ParsedAttributes &attrs) { case tok::kw___uptr: { IdentifierInfo *AttrName = Tok.getIdentifierInfo(); SourceLocation AttrNameLoc = ConsumeToken(); - attrs.addNew(AttrName, AttrNameLoc, nullptr, AttrNameLoc, nullptr, 0, + attrs.addNew(AttrName, AttrNameLoc, AttributeScopeInfo(), nullptr, 0, Kind); break; } @@ -1002,9 +1004,8 @@ void Parser::ParseWebAssemblyFuncrefTypeAttribute(ParsedAttributes &attrs) { IdentifierInfo *AttrName = Tok.getIdentifierInfo(); SourceLocation AttrNameLoc = ConsumeToken(); - attrs.addNew(AttrName, AttrNameLoc, /*ScopeName=*/nullptr, - /*ScopeLoc=*/SourceLocation{}, /*Args=*/nullptr, /*numArgs=*/0, - tok::kw___funcref); + attrs.addNew(AttrName, AttrNameLoc, AttributeScopeInfo(), /*Args=*/nullptr, + /*numArgs=*/0, tok::kw___funcref); } void Parser::DiagnoseAndSkipExtendedMicrosoftTypeAttributes() { @@ -1048,7 +1049,7 @@ void Parser::ParseBorlandTypeAttributes(ParsedAttributes &attrs) { while (Tok.is(tok::kw___pascal)) { IdentifierInfo *AttrName = Tok.getIdentifierInfo(); SourceLocation AttrNameLoc = ConsumeToken(); - attrs.addNew(AttrName, AttrNameLoc, nullptr, AttrNameLoc, nullptr, 0, + attrs.addNew(AttrName, AttrNameLoc, AttributeScopeInfo(), nullptr, 0, tok::kw___pascal); } } @@ -1058,7 +1059,7 @@ void Parser::ParseOpenCLKernelAttributes(ParsedAttributes &attrs) { while (Tok.is(tok::kw___kernel)) { IdentifierInfo *AttrName = Tok.getIdentifierInfo(); SourceLocation AttrNameLoc = ConsumeToken(); - attrs.addNew(AttrName, AttrNameLoc, nullptr, AttrNameLoc, nullptr, 0, + attrs.addNew(AttrName, AttrNameLoc, AttributeScopeInfo(), nullptr, 0, tok::kw___kernel); } } @@ -1067,7 +1068,7 @@ void Parser::ParseCUDAFunctionAttributes(ParsedAttributes &attrs) { while (Tok.is(tok::kw___noinline__)) { IdentifierInfo *AttrName = Tok.getIdentifierInfo(); SourceLocation AttrNameLoc = ConsumeToken(); - attrs.addNew(AttrName, AttrNameLoc, nullptr, AttrNameLoc, nullptr, 0, + attrs.addNew(AttrName, AttrNameLoc, AttributeScopeInfo(), nullptr, 0, tok::kw___noinline__); } } @@ -1075,7 +1076,7 @@ void Parser::ParseCUDAFunctionAttributes(ParsedAttributes &attrs) { void Parser::ParseOpenCLQualifiers(ParsedAttributes &Attrs) { IdentifierInfo *AttrName = Tok.getIdentifierInfo(); SourceLocation AttrNameLoc = Tok.getLocation(); - Attrs.addNew(AttrName, AttrNameLoc, nullptr, AttrNameLoc, nullptr, 0, + Attrs.addNew(AttrName, AttrNameLoc, AttributeScopeInfo(), nullptr, 0, Tok.getKind()); } @@ -1087,7 +1088,7 @@ void Parser::ParseHLSLQualifiers(ParsedAttributes &Attrs) { IdentifierInfo *AttrName = Tok.getIdentifierInfo(); auto Kind = Tok.getKind(); SourceLocation AttrNameLoc = ConsumeToken(); - Attrs.addNew(AttrName, AttrNameLoc, nullptr, AttrNameLoc, nullptr, 0, Kind); + Attrs.addNew(AttrName, AttrNameLoc, AttributeScopeInfo(), nullptr, 0, Kind); } void Parser::ParseNullabilityTypeSpecifiers(ParsedAttributes &attrs) { @@ -1104,7 +1105,7 @@ void Parser::ParseNullabilityTypeSpecifiers(ParsedAttributes &attrs) { if (!getLangOpts().ObjC) Diag(AttrNameLoc, diag::ext_nullability) << AttrName; - attrs.addNew(AttrName, AttrNameLoc, nullptr, AttrNameLoc, nullptr, 0, + attrs.addNew(AttrName, AttrNameLoc, AttributeScopeInfo(), nullptr, 0, Kind); break; } @@ -1448,10 +1449,11 @@ void Parser::ParseAvailabilityAttribute( // Record this attribute attrs.addNew(&Availability, - SourceRange(AvailabilityLoc, T.getCloseLocation()), ScopeName, - ScopeLoc, Platform, Changes[Introduced], Changes[Deprecated], - Changes[Obsoleted], UnavailableLoc, MessageExpr.get(), Form, - StrictLoc, ReplacementExpr.get(), EnvironmentLoc); + SourceRange(AvailabilityLoc, T.getCloseLocation()), + AttributeScopeInfo(ScopeName, ScopeLoc), Platform, + Changes[Introduced], Changes[Deprecated], Changes[Obsoleted], + UnavailableLoc, MessageExpr.get(), Form, StrictLoc, + ReplacementExpr.get(), EnvironmentLoc); } void Parser::ParseExternalSourceSymbolAttribute( @@ -1569,7 +1571,8 @@ void Parser::ParseExternalSourceSymbolAttribute( ArgsUnion Args[] = {Language.get(), DefinedInExpr.get(), GeneratedDeclaration, USR.get()}; Attrs.addNew(&ExternalSourceSymbol, SourceRange(Loc, T.getCloseLocation()), - ScopeName, ScopeLoc, Args, std::size(Args), Form); + AttributeScopeInfo(ScopeName, ScopeLoc), Args, std::size(Args), + Form); } void Parser::ParseObjCBridgeRelatedAttribute( @@ -1637,8 +1640,8 @@ void Parser::ParseObjCBridgeRelatedAttribute( // Record this attribute Attrs.addNew(&ObjCBridgeRelated, SourceRange(ObjCBridgeRelatedLoc, T.getCloseLocation()), - ScopeName, ScopeLoc, RelatedClass, ClassMethod, InstanceMethod, - Form); + AttributeScopeInfo(ScopeName, ScopeLoc), RelatedClass, + ClassMethod, InstanceMethod, Form); } void Parser::ParseSwiftNewTypeAttribute( @@ -1679,7 +1682,8 @@ void Parser::ParseSwiftNewTypeAttribute( ArgsUnion Args[] = {SwiftType}; Attrs.addNew(&AttrName, SourceRange(AttrNameLoc, T.getCloseLocation()), - ScopeName, ScopeLoc, Args, std::size(Args), Form); + AttributeScopeInfo(ScopeName, ScopeLoc), Args, std::size(Args), + Form); } void Parser::ParseTypeTagForDatatypeAttribute( @@ -1732,9 +1736,9 @@ void Parser::ParseTypeTagForDatatypeAttribute( } if (!T.consumeClose()) { - Attrs.addNewTypeTagForDatatype(&AttrName, AttrNameLoc, ScopeName, ScopeLoc, - ArgumentKind, MatchingCType.get(), - LayoutCompatible, MustBeNull, Form); + Attrs.addNewTypeTagForDatatype( + &AttrName, AttrNameLoc, AttributeScopeInfo(ScopeName, ScopeLoc), + ArgumentKind, MatchingCType.get(), LayoutCompatible, MustBeNull, Form); } if (EndLoc) @@ -1842,8 +1846,7 @@ void Parser::ProhibitCXX11Attributes(ParsedAttributes &Attrs, continue; if (AL.getKind() == ParsedAttr::UnknownAttribute) { if (WarnOnUnknownAttrs) - Diag(AL.getLoc(), diag::warn_unknown_attribute_ignored) - << AL << AL.getRange(); + Actions.DiagnoseUnknownAttribute(AL); } else { Diag(AL.getLoc(), AttrDiagID) << AL; AL.setInvalid(); @@ -3130,12 +3133,12 @@ void Parser::ParseAlignmentSpecifier(ParsedAttributes &Attrs, *EndLoc = T.getCloseLocation(); if (IsType) { - Attrs.addNewTypeAttr(KWName, KWLoc, nullptr, KWLoc, TypeResult, Kind, + Attrs.addNewTypeAttr(KWName, KWLoc, AttributeScopeInfo(), TypeResult, Kind, EllipsisLoc); } else { ArgsVector ArgExprs; ArgExprs.push_back(ArgExpr.get()); - Attrs.addNew(KWName, KWLoc, nullptr, KWLoc, ArgExprs.data(), 1, Kind, + Attrs.addNew(KWName, KWLoc, AttributeScopeInfo(), ArgExprs.data(), 1, Kind, EllipsisLoc); } } @@ -3181,9 +3184,8 @@ void Parser::ParsePtrauthQualifier(ParsedAttributes &Attrs) { return; } - Attrs.addNew(KwName, SourceRange(KwLoc, EndLoc), - /*scope*/ nullptr, SourceLocation(), ArgExprs.data(), - ArgExprs.size(), + Attrs.addNew(KwName, SourceRange(KwLoc, EndLoc), AttributeScopeInfo(), + ArgExprs.data(), ArgExprs.size(), ParsedAttr::Form::Keyword(/*IsAlignAs=*/false, /*IsRegularKeywordAttribute=*/false)); } @@ -3231,7 +3233,7 @@ void Parser::ParseBoundsAttribute(IdentifierInfo &AttrName, Ctx.getSizeType(), SourceLocation())); Attrs.addNew(&AttrName, SourceRange(AttrNameLoc, Parens.getCloseLocation()), - ScopeName, ScopeLoc, ArgExprs.data(), ArgExprs.size(), Form); + AttributeScopeInfo(), ArgExprs.data(), ArgExprs.size(), Form); } ExprResult Parser::ParseExtIntegerArgument() { @@ -4010,7 +4012,7 @@ void Parser::ParseDeclarationSpecifiers( isInvalid = DS.setFunctionSpecForceInline(Loc, PrevSpec, DiagID); IdentifierInfo *AttrName = Tok.getIdentifierInfo(); SourceLocation AttrNameLoc = Tok.getLocation(); - DS.getAttributes().addNew(AttrName, AttrNameLoc, nullptr, AttrNameLoc, + DS.getAttributes().addNew(AttrName, AttrNameLoc, AttributeScopeInfo(), nullptr, 0, tok::kw___forceinline); break; } @@ -4068,8 +4070,9 @@ void Parser::ParseDeclarationSpecifiers( // Objective-C 'kindof' types. case tok::kw___kindof: - DS.getAttributes().addNew(Tok.getIdentifierInfo(), Loc, nullptr, Loc, - nullptr, 0, tok::kw___kindof); + DS.getAttributes().addNew(Tok.getIdentifierInfo(), Loc, + AttributeScopeInfo(), nullptr, 0, + tok::kw___kindof); (void)ConsumeToken(); continue; @@ -6254,8 +6257,9 @@ void Parser::ParseTypeQualifierListOpt( // Objective-C 'kindof' types. case tok::kw___kindof: - DS.getAttributes().addNew(Tok.getIdentifierInfo(), Loc, nullptr, Loc, - nullptr, 0, tok::kw___kindof); + DS.getAttributes().addNew(Tok.getIdentifierInfo(), Loc, + AttributeScopeInfo(), nullptr, 0, + tok::kw___kindof); (void)ConsumeToken(); continue; diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index 316bc30edf1f0..2230b9fcad842 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -1435,7 +1435,7 @@ void Parser::ParseMicrosoftInheritanceClassAttributes(ParsedAttributes &attrs) { IdentifierInfo *AttrName = Tok.getIdentifierInfo(); auto Kind = Tok.getKind(); SourceLocation AttrNameLoc = ConsumeToken(); - attrs.addNew(AttrName, AttrNameLoc, nullptr, AttrNameLoc, nullptr, 0, Kind); + attrs.addNew(AttrName, AttrNameLoc, AttributeScopeInfo(), nullptr, 0, Kind); } } @@ -1444,7 +1444,7 @@ void Parser::ParseNullabilityClassAttributes(ParsedAttributes &attrs) { IdentifierInfo *AttrName = Tok.getIdentifierInfo(); auto Kind = Tok.getKind(); SourceLocation AttrNameLoc = ConsumeToken(); - attrs.addNew(AttrName, AttrNameLoc, nullptr, AttrNameLoc, nullptr, 0, Kind); + attrs.addNew(AttrName, AttrNameLoc, AttributeScopeInfo(), nullptr, 0, Kind); } } @@ -4500,8 +4500,8 @@ bool Parser::ParseCXXAssumeAttributeArg(ParsedAttributes &Attrs, ArgsUnion Assumption = Res.get(); auto RParen = Tok.getLocation(); T.consumeClose(); - Attrs.addNew(AttrName, SourceRange(AttrNameLoc, RParen), nullptr, - SourceLocation(), &Assumption, 1, Form); + Attrs.addNew(AttrName, SourceRange(AttrNameLoc, RParen), AttributeScopeInfo(), + &Assumption, 1, Form); if (EndLoc) *EndLoc = RParen; @@ -4580,7 +4580,7 @@ bool Parser::ParseCXX11AttributeArgs( // Ignore attributes that don't exist for the target. if (!Attr.existsInTarget(getTargetInfo())) { - Diag(LParenLoc, diag::warn_unknown_attribute_ignored) << AttrName; + Actions.DiagnoseUnknownAttribute(Attr); Attr.setInvalid(true); return true; } @@ -4635,7 +4635,7 @@ void Parser::ParseCXX11AttributeSpecifierInternal(ParsedAttributes &Attrs, /*ScopeName*/ nullptr, /*ScopeLoc*/ Loc, Form); } else - Attrs.addNew(AttrName, Loc, nullptr, Loc, nullptr, 0, Form); + Attrs.addNew(AttrName, Loc, AttributeScopeInfo(), nullptr, 0, Form); return; } @@ -4656,11 +4656,13 @@ void Parser::ParseCXX11AttributeSpecifierInternal(ParsedAttributes &Attrs, ConsumeBracket(); SourceLocation CommonScopeLoc; + SourceLocation UsingPrefixLoc; IdentifierInfo *CommonScopeName = nullptr; if (Tok.is(tok::kw_using)) { Diag(Tok.getLocation(), getLangOpts().CPlusPlus17 ? diag::warn_cxx14_compat_using_attribute_ns : diag::ext_using_attribute_ns); + UsingPrefixLoc = Tok.getLocation(); ConsumeToken(); CommonScopeName = TryParseCXX11AttributeIdentifier( @@ -4730,12 +4732,15 @@ void Parser::ParseCXX11AttributeSpecifierInternal(ParsedAttributes &Attrs, ScopeName, ScopeLoc, OpenMPTokens); if (!AttrParsed) { - Attrs.addNew( - AttrName, - SourceRange(ScopeLoc.isValid() ? ScopeLoc : AttrLoc, AttrLoc), - ScopeName, ScopeLoc, nullptr, 0, - getLangOpts().CPlusPlus ? ParsedAttr::Form::CXX11() - : ParsedAttr::Form::C23()); + Attrs.addNew(AttrName, + SourceRange(ScopeLoc.isValid() && UsingPrefixLoc.isInvalid() + ? ScopeLoc + : AttrLoc, + AttrLoc), + AttributeScopeInfo(ScopeName, ScopeLoc, UsingPrefixLoc), + nullptr, 0, + getLangOpts().CPlusPlus ? ParsedAttr::Form::CXX11() + : ParsedAttr::Form::C23()); AttrParsed = true; } @@ -4896,8 +4901,8 @@ void Parser::ParseMicrosoftUuidAttributeArgs(ParsedAttributes &Attrs) { } if (!T.consumeClose()) { - Attrs.addNew(UuidIdent, SourceRange(UuidLoc, T.getCloseLocation()), nullptr, - SourceLocation(), ArgExprs.data(), ArgExprs.size(), + Attrs.addNew(UuidIdent, SourceRange(UuidLoc, T.getCloseLocation()), + AttributeScopeInfo(), ArgExprs.data(), ArgExprs.size(), ParsedAttr::Form::Microsoft()); } } @@ -4981,8 +4986,8 @@ void Parser::ParseMicrosoftRootSignatureAttributeArgs(ParsedAttributes &Attrs) { if (!T.consumeClose()) Attrs.addNew(RootSignatureIdent, - SourceRange(RootSignatureLoc, T.getCloseLocation()), nullptr, - SourceLocation(), Args.data(), Args.size(), + SourceRange(RootSignatureLoc, T.getCloseLocation()), + AttributeScopeInfo(), Args.data(), Args.size(), ParsedAttr::Form::Microsoft()); } @@ -5032,7 +5037,7 @@ void Parser::ParseMicrosoftAttributes(ParsedAttributes &Attrs) { ReplayOpenMPAttributeTokens(OpenMPTokens); } if (!AttrParsed) { - Attrs.addNew(II, NameLoc, nullptr, SourceLocation(), nullptr, 0, + Attrs.addNew(II, NameLoc, AttributeScopeInfo(), nullptr, 0, ParsedAttr::Form::Microsoft()); } } diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp index d95260829e4a0..3e9b582fc8387 100644 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -1238,8 +1238,8 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( if (Tok.is(tok::kw___noinline__)) { IdentifierInfo *AttrName = Tok.getIdentifierInfo(); SourceLocation AttrNameLoc = ConsumeToken(); - Attributes.addNew(AttrName, AttrNameLoc, /*ScopeName=*/nullptr, - AttrNameLoc, /*ArgsUnion=*/nullptr, + Attributes.addNew(AttrName, AttrNameLoc, AttributeScopeInfo(), + /*ArgsUnion=*/nullptr, /*numArgs=*/0, tok::kw___noinline__); } else if (Tok.is(tok::kw___attribute)) ParseGNUAttributes(Attributes, /*LatePArsedAttrList=*/nullptr, &D); diff --git a/clang/lib/Parse/ParseHLSL.cpp b/clang/lib/Parse/ParseHLSL.cpp index 5569605c287b1..9cf60a2757170 100644 --- a/clang/lib/Parse/ParseHLSL.cpp +++ b/clang/lib/Parse/ParseHLSL.cpp @@ -295,6 +295,6 @@ void Parser::ParseHLSLAnnotations(ParsedAttributes &Attrs, break; } - Attrs.addNew(II, Loc, nullptr, SourceLocation(), ArgExprs.data(), - ArgExprs.size(), ParsedAttr::Form::HLSLAnnotation()); + Attrs.addNew(II, Loc, AttributeScopeInfo(), ArgExprs.data(), ArgExprs.size(), + ParsedAttr::Form::HLSLAnnotation()); } diff --git a/clang/lib/Parse/ParseObjc.cpp b/clang/lib/Parse/ParseObjc.cpp index ed1a301686bc6..f32a958c3c4f1 100644 --- a/clang/lib/Parse/ParseObjc.cpp +++ b/clang/lib/Parse/ParseObjc.cpp @@ -371,7 +371,7 @@ static void addContextSensitiveTypeNullability(Parser &P, // Create the attribute. auto getNullabilityAttr = [&](AttributePool &Pool) -> ParsedAttr * { return Pool.create(P.getNullabilityKeyword(nullability), - SourceRange(nullabilityLoc), nullptr, SourceLocation(), + SourceRange(nullabilityLoc), AttributeScopeInfo(), nullptr, 0, ParsedAttr::Form::ContextSensitiveKeyword()); }; diff --git a/clang/lib/Parse/ParsePragma.cpp b/clang/lib/Parse/ParsePragma.cpp index 4e67fd033b9aa..85b4adeb1282c 100644 --- a/clang/lib/Parse/ParsePragma.cpp +++ b/clang/lib/Parse/ParsePragma.cpp @@ -1935,7 +1935,7 @@ void Parser::HandlePragmaAttribute() { SourceLocation AttrNameLoc = ConsumeToken(); if (Tok.isNot(tok::l_paren)) - Attrs.addNew(AttrName, AttrNameLoc, nullptr, AttrNameLoc, nullptr, 0, + Attrs.addNew(AttrName, AttrNameLoc, AttributeScopeInfo(), nullptr, 0, ParsedAttr::Form::GNU()); else ParseGNUAttributeArgs(AttrName, AttrNameLoc, Attrs, /*EndLoc=*/nullptr, diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp index c788723023c8b..42f3bd29bafdf 100644 --- a/clang/lib/Parse/ParseStmt.cpp +++ b/clang/lib/Parse/ParseStmt.cpp @@ -2349,8 +2349,8 @@ StmtResult Parser::ParsePragmaLoopHint(StmtVector &Stmts, ArgsUnion ArgHints[] = {Hint.PragmaNameLoc, Hint.OptionLoc, Hint.StateLoc, ArgsUnion(Hint.ValueExpr)}; TempAttrs.addNew(Hint.PragmaNameLoc->getIdentifierInfo(), Hint.Range, - /*scopeName=*/nullptr, Hint.PragmaNameLoc->getLoc(), - ArgHints, /*numArgs=*/4, ParsedAttr::Form::Pragma()); + AttributeScopeInfo(), ArgHints, /*numArgs=*/4, + ParsedAttr::Form::Pragma()); } // Get the next statement. diff --git a/clang/lib/Sema/SemaAPINotes.cpp b/clang/lib/Sema/SemaAPINotes.cpp index def909fc2478d..f21cbbbdb44ee 100644 --- a/clang/lib/Sema/SemaAPINotes.cpp +++ b/clang/lib/Sema/SemaAPINotes.cpp @@ -303,10 +303,9 @@ static void ProcessAPINotes(Sema &S, Decl *D, AttributeFactory AF{}; AttributePool AP{AF}; auto &C = S.getASTContext(); - ParsedAttr *SNA = - AP.create(&C.Idents.get("swift_name"), SourceRange(), nullptr, - SourceLocation(), nullptr, nullptr, nullptr, - ParsedAttr::Form::GNU()); + ParsedAttr *SNA = AP.create( + &C.Idents.get("swift_name"), SourceRange(), AttributeScopeInfo(), + nullptr, nullptr, nullptr, ParsedAttr::Form::GNU()); if (!S.Swift().DiagnoseName(D, Info.SwiftName, D->getLocation(), *SNA, /*IsAsync=*/false)) diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 8ce51cc2882bf..57a6d1b820d3a 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -1971,14 +1971,13 @@ bool Sema::CheckAttrNoArgs(const ParsedAttr &Attrs) { bool Sema::CheckAttrTarget(const ParsedAttr &AL) { // Check whether the attribute is valid on the current target. if (!AL.existsInTarget(Context.getTargetInfo())) { - Diag(AL.getLoc(), AL.isRegularKeywordAttribute() - ? diag::err_keyword_not_supported_on_target - : diag::warn_unknown_attribute_ignored) - << AL << AL.getRange(); + if (AL.isRegularKeywordAttribute()) + Diag(AL.getLoc(), diag::err_keyword_not_supported_on_target); + else + DiagnoseUnknownAttribute(AL); AL.setInvalid(); return true; } - return false; } @@ -7848,8 +7847,7 @@ static void checkUnusedDeclAttributes(Sema &S, const ParsedAttributesView &A) { continue; if (AL.getKind() == ParsedAttr::UnknownAttribute) { - S.Diag(AL.getLoc(), diag::warn_unknown_attribute_ignored) - << AL << AL.getRange(); + S.DiagnoseUnknownAttribute(AL); } else { S.Diag(AL.getLoc(), diag::warn_attribute_not_on_decl) << AL << AL.getRange(); @@ -7867,15 +7865,45 @@ void Sema::checkUnusedDeclAttributes(Declarator &D) { void Sema::DiagnoseUnknownAttribute(const ParsedAttr &AL) { std::string NormalizedFullName = '\'' + AL.getNormalizedFullName() + '\''; - if (auto CorrectedFullName = - AL.getCorrectedFullName(Context.getTargetInfo(), getLangOpts())) { - Diag(AL.getNormalizedRange().getBegin(), - diag::warn_unknown_attribute_ignored_suggestion) - << NormalizedFullName << *CorrectedFullName << AL.getNormalizedRange(); + SourceRange NR = AL.getNormalizedRange(); + + StringRef ScopeName = AL.getNormalizedScopeName(); + std::optional<StringRef> CorrectedScopeName = + AL.tryGetCorrectedScopeName(ScopeName); + if (CorrectedScopeName) { + ScopeName = *CorrectedScopeName; + } + + StringRef AttrName = AL.getNormalizedAttrName(ScopeName); + std::optional<StringRef> CorrectedAttrName = AL.tryGetCorrectedAttrName( + ScopeName, AttrName, Context.getTargetInfo(), getLangOpts()); + if (CorrectedAttrName) { + AttrName = *CorrectedAttrName; + } + + if (CorrectedScopeName || CorrectedAttrName) { + std::string CorrectedFullName = + AL.getNormalizedFullName(ScopeName, AttrName); + SemaDiagnosticBuilder D = + Diag(CorrectedScopeName ? NR.getBegin() : AL.getRange().getBegin(), + diag::warn_unknown_attribute_ignored_suggestion); + + D << NormalizedFullName << CorrectedFullName; + + if (AL.isExplicitScope()) { + D << FixItHint::CreateReplacement(NR, CorrectedFullName) << NR; + } else { + if (CorrectedScopeName) { + D << FixItHint::CreateReplacement(SourceRange(AL.getScopeLoc()), + ScopeName); + } + if (CorrectedAttrName) { + D << FixItHint::CreateReplacement(AL.getRange(), AttrName); + } + } } else { - Diag(AL.getNormalizedRange().getBegin(), - diag::warn_unknown_attribute_ignored) - << NormalizedFullName << AL.getNormalizedRange(); + Diag(NR.getBegin(), diag::warn_unknown_attribute_ignored) + << NormalizedFullName << NR; } } diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index ead53a995dff1..a4ebae4a2cff6 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -2867,8 +2867,7 @@ BaseResult Sema::ActOnBaseSpecifier(Decl *classdecl, SourceRange SpecifierRange, if (AL.isInvalid() || AL.getKind() == ParsedAttr::IgnoredAttribute) continue; if (AL.getKind() == ParsedAttr::UnknownAttribute) - Diag(AL.getLoc(), diag::warn_unknown_attribute_ignored) - << AL << AL.getRange(); + DiagnoseUnknownAttribute(AL); else Diag(AL.getLoc(), diag::err_base_specifier_attribute) << AL << AL.isRegularKeywordAttribute() << AL.getRange(); diff --git a/clang/lib/Sema/SemaStmtAttr.cpp b/clang/lib/Sema/SemaStmtAttr.cpp index 17da5fd8325be..53df84c7608ca 100644 --- a/clang/lib/Sema/SemaStmtAttr.cpp +++ b/clang/lib/Sema/SemaStmtAttr.cpp @@ -672,12 +672,14 @@ static Attr *ProcessStmtAttribute(Sema &S, Stmt *St, const ParsedAttr &A, !(A.existsInTarget(S.Context.getTargetInfo()) || (S.Context.getLangOpts().SYCLIsDevice && Aux && A.existsInTarget(*Aux)))) { - S.Diag(A.getLoc(), A.isRegularKeywordAttribute() - ? (unsigned)diag::err_keyword_not_supported_on_target - : A.isDeclspecAttribute() - ? (unsigned)diag::warn_unhandled_ms_attribute_ignored - : (unsigned)diag::warn_unknown_attribute_ignored) - << A << A.getRange(); + if (A.isRegularKeywordAttribute() || A.isDeclspecAttribute()) { + S.Diag(A.getLoc(), A.isRegularKeywordAttribute() + ? diag::err_keyword_not_supported_on_target + : diag::warn_unhandled_ms_attribute_ignored) + << A << A.getRange(); + } else { + S.DiagnoseUnknownAttribute(A); + } return nullptr; } diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 874e41ac0b90c..710aaee32acef 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -4555,7 +4555,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, false /*IsRegularKeywordAttribute*/); ParsedAttr *nullabilityAttr = Pool.create( S.getNullabilityKeyword(*inferNullability), SourceRange(pointerLoc), - nullptr, SourceLocation(), nullptr, 0, form); + AttributeScopeInfo(), nullptr, 0, form); attrs.addAtEnd(nullabilityAttr); @@ -5738,10 +5738,10 @@ static void transferARCOwnershipToDeclaratorChunk(TypeProcessingState &state, // If there wasn't one, add one (with an invalid source location // so that we don't make an AttributedType for it). - ParsedAttr *attr = D.getAttributePool().create( - &S.Context.Idents.get("objc_ownership"), SourceLocation(), - /*scope*/ nullptr, SourceLocation(), - /*args*/ &Args, 1, ParsedAttr::Form::GNU()); + ParsedAttr *attr = + D.getAttributePool().create(&S.Context.Idents.get("objc_ownership"), + SourceLocation(), AttributeScopeInfo(), + /*args*/ &Args, 1, ParsedAttr::Form::GNU()); chunk.getAttrs().addAtEnd(attr); // TODO: mark whether we did this inference? } diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp index e84932c765663..2b9e2b70127d9 100644 --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -3201,8 +3201,8 @@ Attr *ASTRecordReader::readAttr() { SpellingIndex == AlignedAttr::Keyword_alignas); bool IsRegularKeywordAttribute = Record.readBool(); - AttributeCommonInfo Info(AttrName, ScopeName, AttrRange, ScopeLoc, - AttributeCommonInfo::Kind(ParsedKind), + AttributeCommonInfo Info(AttrName, AttributeScopeInfo(ScopeName, ScopeLoc), + AttrRange, AttributeCommonInfo::Kind(ParsedKind), {AttributeCommonInfo::Syntax(Syntax), SpellingIndex, IsAlignas, IsRegularKeywordAttribute}); diff --git a/clang/test/CXX/module/dcl.dcl/dcl.module/dcl.module.import/p1.cppm b/clang/test/CXX/module/dcl.dcl/dcl.module/dcl.module.import/p1.cppm index 873e4c0edeac2..3670f9430ed4b 100644 --- a/clang/test/CXX/module/dcl.dcl/dcl.module/dcl.module.import/p1.cppm +++ b/clang/test/CXX/module/dcl.dcl/dcl.module/dcl.module.import/p1.cppm @@ -45,7 +45,7 @@ import x; import x [[]]; import x [[foo]]; // expected-warning {{unknown attribute 'foo' ignored}} import x [[noreturn]]; // expected-error {{'noreturn' attribute cannot be applied to a module import}} -import x [[blarg::noreturn]]; // expected-warning {{unknown attribute 'noreturn' ignored}} +import x [[blarg::noreturn]]; // expected-warning {{unknown attribute 'blarg::noreturn' ignored}} import x.y; import x.; // expected-error {{expected a module name after 'import'}} diff --git a/clang/test/FixIt/fixit-unknown-attributes.cpp b/clang/test/FixIt/fixit-unknown-attributes.cpp new file mode 100644 index 0000000000000..a25eae3d47419 --- /dev/null +++ b/clang/test/FixIt/fixit-unknown-attributes.cpp @@ -0,0 +1,60 @@ +// RUN: %clang_cc1 -Wunknown-attributes -fsyntax-only -verify %s +// RUN: %clang_cc1 -Wunknown-attributes -fsyntax-only -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s + +[[gmu::deprected]] // expected-warning {{unknown attribute 'gmu::deprected' ignored; did you mean 'gnu::deprecated'?}} +int f1(void) { + return 0; +} +// CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:3-[[@LINE-4]]:17}:"gnu::deprecated" + +[[gmu::deprecated]] // expected-warning {{unknown attribute 'gmu::deprecated' ignored; did you mean 'gnu::deprecated'?}} +int f2(void) { + return 0; +} +// CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:3-[[@LINE-4]]:18}:"gnu::deprecated" + +[[gnu::deprected]] // expected-warning {{unknown attribute 'gnu::deprected' ignored; did you mean 'gnu::deprecated'?}} +int f3(void) { + return 0; +} +// CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:3-[[@LINE-4]]:17}:"gnu::deprecated" + +[[deprected]] // expected-warning {{unknown attribute 'deprected' ignored; did you mean 'deprecated'?}} +int f4(void) { + return 0; +} +// CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:3-[[@LINE-4]]:12}:"deprecated" + +[[using gmu : deprected]] // expected-warning {{unknown attribute 'gmu::deprected' ignored; did you mean 'gnu::deprecated'?}} +int f5(void) { + return 0; +} +// CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:9-[[@LINE-4]]:12}:"gnu" +// CHECK-NEXT: fix-it:"{{.*}}":{[[@LINE-5]]:15-[[@LINE-5]]:24}:"deprecated" + +[[using gmu : deprecated]] // expected-warning {{unknown attribute 'gmu::deprecated' ignored; did you mean 'gnu::deprecated'?}} +int f6(void) { + return 0; +} +// CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:9-[[@LINE-4]]:12}:"gnu" + +[[using gnu : deprected]] // expected-warning {{unknown attribute 'gnu::deprected' ignored; did you mean 'gnu::deprecated'?}} +int f7(void) { + return 0; +} +// CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:15-[[@LINE-4]]:24}:"deprecated" + +[[using gnu : deprecated, noretyrn]] // expected-warning {{unknown attribute 'gnu::noretyrn' ignored; did you mean 'gnu::noreturn'?}} +void f8(void) { +} +// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:27-[[@LINE-3]]:35}:"noreturn" + +[[using gmu : deprected, noretyrn]] // expected-warning {{unknown attribute 'gmu::deprected' ignored; did you mean 'gnu::deprecated'?}} \ + // expected-warning {{unknown attribute 'gmu::noretyrn' ignored; did you mean 'gnu::noreturn'?}} +void f9(void) { +} +// CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:9-[[@LINE-4]]:12}:"gnu" +// CHECK-NEXT: fix-it:"{{.*}}":{[[@LINE-5]]:15-[[@LINE-5]]:24}:"deprecated" + +// CHECK: fix-it:"{{.*}}":{[[@LINE-7]]:9-[[@LINE-7]]:12}:"gnu" +// CHECK-NEXT: fix-it:"{{.*}}":{[[@LINE-8]]:26-[[@LINE-8]]:34}:"noreturn" diff --git a/clang/test/Parser/cxx11-base-spec-attributes.cpp b/clang/test/Parser/cxx11-base-spec-attributes.cpp index 7338c5116c16c..6f2f54ead62bc 100644 --- a/clang/test/Parser/cxx11-base-spec-attributes.cpp +++ b/clang/test/Parser/cxx11-base-spec-attributes.cpp @@ -7,4 +7,4 @@ struct D : [[]] public virtual A {}; struct E : public [[]] virtual A {}; // expected-error {{an attribute list cannot appear here}} struct F : virtual [[]] public A {}; // expected-error {{an attribute list cannot appear here}} struct G : [[noreturn]] A {}; // expected-error {{'noreturn' attribute cannot be applied to a base specifier}} -struct H : [[unknown::foobar]] A {}; // expected-warning {{unknown attribute 'foobar' ignored}} +struct H : [[unknown::foobar]] A {}; // expected-warning {{unknown attribute 'unknown::foobar' ignored}} diff --git a/clang/test/Parser/objcxx11-attributes.mm b/clang/test/Parser/objcxx11-attributes.mm index d7ba609ebd74b..88fa3103593ef 100644 --- a/clang/test/Parser/objcxx11-attributes.mm +++ b/clang/test/Parser/objcxx11-attributes.mm @@ -57,7 +57,7 @@ void f(X *noreturn) { template<typename...Ts> void f(Ts ...x) { [[test::foo(bar, baz)...]]; // expected-error {{attribute 'foo' cannot be used as an attribute pack}} \ - // expected-warning {{unknown attribute 'foo' ignored}} + // expected-warning {{unknown attribute 'test::foo' ignored}} [[used(x)...]]; // expected-error {{attribute 'used' cannot be used as an attribute pack}} \ // expected-warning {{unknown attribute 'used' ignored}} diff --git a/clang/test/Sema/unknown-attributes.c b/clang/test/Sema/unknown-attributes.c index a701650c9e056..4711c9fa667ba 100644 --- a/clang/test/Sema/unknown-attributes.c +++ b/clang/test/Sema/unknown-attributes.c @@ -1,5 +1,5 @@ -// RUN: %clang_cc1 -Wunknown-attributes -fsyntax-only -verify %s -// RUN: %clang_cc1 -x c++ -Wunknown-attributes -fsyntax-only -verify %s +// RUN: %clang_cc1 -Wunknown-attributes -fsyntax-only -verify=expected,c %s +// RUN: %clang_cc1 -x c++ -Wunknown-attributes -fsyntax-only -verify=expected,cxx %s [[gmu::deprected]] // expected-warning {{unknown attribute 'gmu::deprected' ignored; did you mean 'gnu::deprecated'?}} int f1(void) { @@ -20,3 +20,10 @@ int f3(void) { int f4(void) { return 0; } + +[[using gnu : deprected]] // c-error {{expected ','}} \ + // c-warning {{unknown attribute 'using' ignored}} \ + // cxx-warning {{unknown attribute 'gnu::deprected' ignored; did you mean 'gnu::deprecated'?}} +int f5(void) { + return 0; +} diff --git a/clang/test/SemaCXX/attr-non-x86-no_caller_saved_registers.cpp b/clang/test/SemaCXX/attr-non-x86-no_caller_saved_registers.cpp index 00fa5bd7336b6..acd9846bb20fb 100644 --- a/clang/test/SemaCXX/attr-non-x86-no_caller_saved_registers.cpp +++ b/clang/test/SemaCXX/attr-non-x86-no_caller_saved_registers.cpp @@ -11,7 +11,7 @@ __attribute__((no_caller_saved_registers(999))) void bar(int *) {} // expected-w __attribute__((no_caller_saved_registers)) void foo(int *){} // expected-warning {{unknown attribute 'no_caller_saved_registers' ignored}} -[[gnu::no_caller_saved_registers]] void foo2(int *) {} // expected-warning {{unknown attribute 'no_caller_saved_registers' ignored}} +[[gnu::no_caller_saved_registers]] void foo2(int *) {} // expected-warning {{unknown attribute 'gnu::no_caller_saved_registers' ignored}} typedef __attribute__((no_caller_saved_registers)) void (*foo3)(int *); // expected-warning {{unknown attribute 'no_caller_saved_registers' ignored}} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits