[clang] [Clang] add fix-it hints for unknown attributes (PR #141305)
Oleksandr T. via cfe-commits
cfe-commits at lists.llvm.org
Fri May 30 17:07:12 PDT 2025
https://github.com/a-tarasyuk updated https://github.com/llvm/llvm-project/pull/141305
>From 09959fcdf22c15cbe7edadf6e303d77c8573e607 Mon Sep 17 00:00:00 2001
From: Oleksandr Tarasiuk <oleksandr.tarasiuk at outlook.com>
Date: Sat, 31 May 2025 02:54:22 +0300
Subject: [PATCH] [Clang] add fix-it hints for unknown attributes
---
clang/docs/ReleaseNotes.rst | 2 +
.../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 | 55 ++++--
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, 406 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 dc97883de05d0..b26b8aca268e8 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -601,6 +601,8 @@ Improvements to Clang's diagnostics
trigger a ``'Blue' is deprecated`` warning, which can be turned off with
``-Wno-deprecated-declarations-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 003bad225e30c..5c44353d8b987 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -9333,8 +9333,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..171be39743bc6 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,23 @@ 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 +209,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 +257,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 +267,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 d6c36616bab47..a1c48cbd0c134 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -151,7 +151,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;
}
@@ -396,12 +396,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
@@ -621,10 +621,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);
}
}
@@ -866,7 +868,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();
@@ -952,7 +954,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();
@@ -980,7 +982,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;
}
@@ -1001,9 +1003,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() {
@@ -1047,7 +1048,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);
}
}
@@ -1057,7 +1058,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);
}
}
@@ -1066,7 +1067,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__);
}
}
@@ -1074,7 +1075,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());
}
@@ -1086,7 +1087,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) {
@@ -1103,7 +1104,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;
}
@@ -1447,10 +1448,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(
@@ -1568,7 +1570,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(
@@ -1636,8 +1639,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(
@@ -1678,7 +1681,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(
@@ -1731,9 +1735,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)
@@ -1841,8 +1845,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();
@@ -3129,12 +3132,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);
}
}
@@ -3180,9 +3183,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));
}
@@ -3230,7 +3232,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() {
@@ -4009,7 +4011,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;
}
@@ -4067,8 +4069,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;
@@ -6253,8 +6256,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 2cf33a856c4f4..eeb6f18ab3ff7 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -1433,7 +1433,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);
}
}
@@ -1442,7 +1442,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);
}
}
@@ -4497,8 +4497,8 @@ bool Parser::ParseCXXAssumeAttributeArg(
ArgsUnion Assumption = Res.get();
auto RParen = Tok.getLocation();
T.consumeClose();
- Attrs.addNew(AttrName, SourceRange(AttrNameLoc, RParen), ScopeName, ScopeLoc,
- &Assumption, 1, Form);
+ Attrs.addNew(AttrName, SourceRange(AttrNameLoc, RParen),
+ AttributeScopeInfo(ScopeName, ScopeLoc), &Assumption, 1, Form);
if (EndLoc)
*EndLoc = RParen;
@@ -4578,7 +4578,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;
}
@@ -4633,7 +4633,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;
}
@@ -4654,11 +4654,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(
@@ -4728,12 +4730,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;
}
@@ -4894,8 +4899,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());
}
}
@@ -4979,8 +4984,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());
}
@@ -5030,7 +5035,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 6afb7809d3cd2..b108e30a47c4f 100644
--- a/clang/lib/Parse/ParseObjc.cpp
+++ b/clang/lib/Parse/ParseObjc.cpp
@@ -370,7 +370,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 77b61af768993..7f9982ee837e6 100644
--- a/clang/lib/Parse/ParsePragma.cpp
+++ b/clang/lib/Parse/ParsePragma.cpp
@@ -1931,7 +1931,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 119ba8486b09f..a618adc60200b 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;
}
@@ -7867,8 +7866,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();
@@ -7886,15 +7884,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 4a735992cec68..261ec8f38ac2a 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -2866,8 +2866,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 338b81fe89748..df9fb8114b58f 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}}
More information about the cfe-commits
mailing list