From 574efb02fa1955f58bb0f9c7b4594cbbd972da45 Mon Sep 17 00:00:00 2001 From: Aaron Ballman <aaron@aaronballman.com> Date: Thu, 26 Dec 2013 18:30:57 +0000 Subject: [PATCH] Teach the diagnostics engine about the Attr type to make reporting on semantic attributes easier (and not require hard-coded strings). This requires a getSpelling() function on the Attr class, which is table-driven. Updates a handful of cases where a hard-coded string was being used to test the functionality out. Updating associated test cases for the improved quoting. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@198055 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/Attr.h | 14 ++++++++++++ include/clang/Basic/Diagnostic.h | 3 ++- include/clang/Basic/DiagnosticSemaKinds.td | 2 +- lib/AST/ASTDiagnostic.cpp | 9 ++++++++ lib/Basic/Diagnostic.cpp | 1 + lib/Sema/SemaDecl.cpp | 6 +++--- lib/Sema/SemaDeclAttr.cpp | 18 +++++++--------- test/Rewriter/missing-dllimport.c | 2 +- test/Sema/dllimport-dllexport.c | 8 +++---- test/SemaCXX/MicrosoftExtensions.cpp | 20 ++++++++--------- utils/TableGen/ClangAttrEmitter.cpp | 25 ++++++++++++++++++++++ 11 files changed, 78 insertions(+), 30 deletions(-) diff --git a/include/clang/AST/Attr.h b/include/clang/AST/Attr.h index d5dc537baf2..61130b5dc12 100644 --- a/include/clang/AST/Attr.h +++ b/include/clang/AST/Attr.h @@ -85,6 +85,7 @@ public: } unsigned getSpellingListIndex() const { return SpellingListIndex; } + virtual const char *getSpelling() const = 0; SourceLocation getLocation() const { return Range.getBegin(); } SourceRange getRange() const { return Range; } @@ -138,6 +139,19 @@ public: #include "clang/AST/Attrs.inc" +inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, + const Attr *At) { + DB.AddTaggedVal(reinterpret_cast<intptr_t>(At), + DiagnosticsEngine::ak_attr); + return DB; +} + +inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD, + const Attr *At) { + PD.AddTaggedVal(reinterpret_cast<intptr_t>(At), + DiagnosticsEngine::ak_attr); + return PD; +} } // end namespace clang #endif diff --git a/include/clang/Basic/Diagnostic.h b/include/clang/Basic/Diagnostic.h index 2b0b3f9b28c..97f2e80244c 100644 --- a/include/clang/Basic/Diagnostic.h +++ b/include/clang/Basic/Diagnostic.h @@ -166,7 +166,8 @@ public: ak_nameddecl, ///< NamedDecl * ak_nestednamespec, ///< NestedNameSpecifier * ak_declcontext, ///< DeclContext * - ak_qualtype_pair ///< pair<QualType, QualType> + ak_qualtype_pair, ///< pair<QualType, QualType> + ak_attr ///< Attr * }; /// \brief Represents on argument value, which is a union discriminated diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 54a4159ee6d..c3ac6fbd78e 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -6722,7 +6722,7 @@ def err_opencl_global_invalid_addr_space : Error< "global variables must have a constant address space qualifier">; def err_opencl_no_main : Error<"%select{function|kernel}0 cannot be called 'main'">; def err_opencl_kernel_attr : - Error<"attribute '%0' can only be applied to a kernel function">; + Error<"attribute %0 can only be applied to a kernel function">; } // end of sema category let CategoryName = "OpenMP Issue" in { diff --git a/lib/AST/ASTDiagnostic.cpp b/lib/AST/ASTDiagnostic.cpp index 7f7221fc6ed..f3c2b224e1d 100644 --- a/lib/AST/ASTDiagnostic.cpp +++ b/lib/AST/ASTDiagnostic.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "clang/AST/ASTDiagnostic.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/Attr.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/ExprCXX.h" @@ -359,6 +360,14 @@ void clang::FormatASTNodeDiagnosticArgument( NeedQuotes = false; break; } + case DiagnosticsEngine::ak_attr: { + const Attr *At = reinterpret_cast<Attr *>(Val); + assert(At && "Received null Attr object!"); + OS << '\'' << At->getSpelling() << '\''; + NeedQuotes = false; + break; + } + } OS.flush(); diff --git a/lib/Basic/Diagnostic.cpp b/lib/Basic/Diagnostic.cpp index 4a6f070af70..eaae388fd8d 100644 --- a/lib/Basic/Diagnostic.cpp +++ b/lib/Basic/Diagnostic.cpp @@ -861,6 +861,7 @@ FormatDiagnostic(const char *DiagStr, const char *DiagEnd, case DiagnosticsEngine::ak_nameddecl: case DiagnosticsEngine::ak_nestednamespec: case DiagnosticsEngine::ak_declcontext: + case DiagnosticsEngine::ak_attr: getDiags()->ConvertArgToString(Kind, getRawArg(ArgNo), Modifier, ModifierLen, Argument, ArgumentLen, diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 9ed9510a659..fd576f3d5ad 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -8934,7 +8934,7 @@ Sema::FinalizeDeclaration(Decl *ThisDecl) { if (UsedAttr *Attr = VD->getAttr<UsedAttr>()) { if (!Attr->isInherited() && !VD->isThisDeclarationADefinition()) { - Diag(Attr->getLocation(), diag::warn_attribute_ignored) << "'used'"; + Diag(Attr->getLocation(), diag::warn_attribute_ignored) << Attr; VD->dropAttr<UsedAttr>(); } } @@ -9674,7 +9674,7 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D) { !(LangOpts.MicrosoftExt && FD->getLexicalDeclContext()->isRecord())) { Diag(FD->getLocation(), diag::err_attribute_can_be_applied_only_to_symbol_declaration) - << "dllimport"; + << DA; FD->setInvalidDecl(); return D; } @@ -9687,7 +9687,7 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D) { // emitted. Diag(FD->getLocation(), diag::warn_redeclaration_without_attribute_prev_attribute_ignored) - << FD->getName() << "dllimport"; + << FD->getName() << DA; } } // We want to attach documentation to original Decl (which might be diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index 26988b23268..56e8725ab6f 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -1557,8 +1557,8 @@ static void handleVecReturnAttr(Sema &S, Decl *D, const AttributeList &Attr) { return result; // This will be returned in a register } */ - if (D->hasAttr<VecReturnAttr>()) { - S.Diag(Attr.getLoc(), diag::err_repeat_attribute) << "vecreturn"; + if (VecReturnAttr *A = D->getAttr<VecReturnAttr>()) { + S.Diag(Attr.getLoc(), diag::err_repeat_attribute) << A; return; } @@ -4127,18 +4127,16 @@ void Sema::ProcessDeclAttributeList(Scope *S, Decl *D, if (!D->hasAttr<OpenCLKernelAttr>()) { // These attributes cannot be applied to a non-kernel function. - if (D->hasAttr<ReqdWorkGroupSizeAttr>()) { - Diag(D->getLocation(), diag::err_opencl_kernel_attr) - << "reqd_work_group_size"; + if (Attr *A = D->getAttr<ReqdWorkGroupSizeAttr>()) { + Diag(D->getLocation(), diag::err_opencl_kernel_attr) << A; D->setInvalidDecl(); } - if (D->hasAttr<WorkGroupSizeHintAttr>()) { - Diag(D->getLocation(), diag::err_opencl_kernel_attr) - << "work_group_size_hint"; + if (Attr *A = D->getAttr<WorkGroupSizeHintAttr>()) { + Diag(D->getLocation(), diag::err_opencl_kernel_attr) << A; D->setInvalidDecl(); } - if (D->hasAttr<VecTypeHintAttr>()) { - Diag(D->getLocation(), diag::err_opencl_kernel_attr) << "vec_type_hint"; + if (Attr *A = D->getAttr<VecTypeHintAttr>()) { + Diag(D->getLocation(), diag::err_opencl_kernel_attr) << A; D->setInvalidDecl(); } } diff --git a/test/Rewriter/missing-dllimport.c b/test/Rewriter/missing-dllimport.c index 127989b0ed8..1e4689fba0d 100644 --- a/test/Rewriter/missing-dllimport.c +++ b/test/Rewriter/missing-dllimport.c @@ -13,7 +13,7 @@ void bar() { return 1; } // CHECK-NEG: error: void function 'bar' should not return a value // CHECK-NEG: 1 error generated -// CHECK-POS: warning: 'foo' redeclared without dllimport attribute: previous dllimport ignored +// CHECK-POS: warning: 'foo' redeclared without 'dllimport' attribute: previous 'dllimport' ignored // CHECK-POS: error: void function 'bar' should not return a value // CHECK-POS: 1 warning and 1 error generated diff --git a/test/Sema/dllimport-dllexport.c b/test/Sema/dllimport-dllexport.c index 198c25f90ca..e93507846e6 100644 --- a/test/Sema/dllimport-dllexport.c +++ b/test/Sema/dllimport-dllexport.c @@ -4,7 +4,7 @@ inline void __attribute__((dllexport)) foo1(){} // expected-warning{{'dllexport' attribute ignored}} inline void __attribute__((dllimport)) foo2(){} // expected-warning{{'dllimport' attribute ignored}} -void __attribute__((dllimport)) foo3(){} // expected-error{{dllimport attribute can be applied only to symbol declaration}} +void __attribute__((dllimport)) foo3(){} // expected-error{{'dllimport' attribute can be applied only to symbol declaration}} void __attribute__((dllimport, dllexport)) foo4(); // expected-warning{{dllimport attribute ignored}} @@ -16,13 +16,13 @@ typedef int __attribute__((dllexport)) type6; // expected-warning{{'dllexport' a typedef int __attribute__((dllimport)) type7; // expected-warning{{'dllimport' attribute only applies to variables and functions}} void __attribute__((dllimport)) foo6(); -void foo6(){} // expected-warning {{'foo6' redeclared without dllimport attribute: previous dllimport ignored}} +void foo6(){} // expected-warning {{'foo6' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} // PR6269 inline void __declspec(dllexport) foo7(){} // expected-warning{{'dllexport' attribute ignored}} inline void __declspec(dllimport) foo8(){} // expected-warning{{'dllimport' attribute ignored}} -void __declspec(dllimport) foo9(){} // expected-error{{dllimport attribute can be applied only to symbol declaration}} +void __declspec(dllimport) foo9(){} // expected-error{{'dllimport' attribute can be applied only to symbol declaration}} void __declspec(dllimport) __declspec(dllexport) foo10(); // expected-warning{{dllimport attribute ignored}} @@ -34,7 +34,7 @@ typedef int __declspec(dllexport) type1; // expected-warning{{'dllexport' attrib typedef int __declspec(dllimport) type2; // expected-warning{{'dllimport' attribute only applies to variables and functions}} void __declspec(dllimport) foo12(); -void foo12(){} // expected-warning {{'foo12' redeclared without dllimport attribute: previous dllimport ignored}} +void foo12(){} // expected-warning {{'foo12' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} void __attribute__((dllimport)) foo13(); // expected-warning{{dllimport attribute ignored}} void __attribute__((dllexport)) foo13(); diff --git a/test/SemaCXX/MicrosoftExtensions.cpp b/test/SemaCXX/MicrosoftExtensions.cpp index 5c51331500b..32b8adb5df3 100644 --- a/test/SemaCXX/MicrosoftExtensions.cpp +++ b/test/SemaCXX/MicrosoftExtensions.cpp @@ -37,11 +37,11 @@ class B : public A { // MSVC allows type definition in anonymous union and struct struct A { - union + union { int a; struct B // expected-warning {{types declared in an anonymous union are a Microsoft extension}} - { + { int c; } d; @@ -63,7 +63,7 @@ struct A { int c2; } d2; - + union C2 // expected-warning {{types declared in an anonymous struct are a Microsoft extension}} { int e2; @@ -78,7 +78,7 @@ struct A // __stdcall handling struct M { int __stdcall addP(); - float __stdcall subtractP(); + float __stdcall subtractP(); }; // __unaligned handling @@ -90,7 +90,7 @@ template<typename T> void h1(T (__stdcall M::* const )()) { } void m1() { h1<int>(&M::addP); h1(&M::subtractP); -} +} @@ -98,7 +98,7 @@ void m1() { void f(long long); void f(int); - + int main() { // This is an ambiguous call in standard C++. @@ -126,7 +126,7 @@ __declspec(dllimport) void f(void) { } void f2(void); }; -__declspec(dllimport) void AAA::f2(void) { // expected-error {{dllimport attribute can be applied only to symbol}} +__declspec(dllimport) void AAA::f2(void) { // expected-error {{'dllimport' attribute can be applied only to symbol}} } @@ -368,18 +368,18 @@ struct StructWithUnnamedMember { namespace rdar14250378 { class Bar {}; - + namespace NyNamespace { class Foo { public: Bar* EnsureBar(); }; - + class Baz : public Foo { public: friend class Bar; }; - + Bar* Foo::EnsureBar() { return 0; } diff --git a/utils/TableGen/ClangAttrEmitter.cpp b/utils/TableGen/ClangAttrEmitter.cpp index d32f3a61e88..ef753946da4 100644 --- a/utils/TableGen/ClangAttrEmitter.cpp +++ b/utils/TableGen/ClangAttrEmitter.cpp @@ -954,6 +954,29 @@ static void writeAvailabilityValue(raw_ostream &OS) { << " OS << \""; } +static void writeGetSpellingFunction(Record &R, raw_ostream &OS) { + std::vector<Record *> Spellings = R.getValueAsListOfDefs("Spellings"); + + OS << "const char *" << R.getName() << "Attr::getSpelling() const {\n"; + if (Spellings.empty()) { + OS << " return \"(No spelling)\";\n}\n\n"; + return; + } + + OS << " switch (SpellingListIndex) {\n" + " default:\n" + " llvm_unreachable(\"Unknown attribute spelling!\");\n" + " return \"(No spelling)\";\n"; + + for (unsigned I = 0; I < Spellings.size(); ++I) + OS << " case " << I << ":\n" + " return \"" << Spellings[I]->getValueAsString("Name") << "\";\n"; + // End of the switch statement. + OS << " }\n"; + // End of the getSpelling function. + OS << "}\n\n"; +} + static void writePrettyPrintFunction(Record &R, std::vector<Argument*> &Args, raw_ostream &OS) { std::vector<Record*> Spellings = R.getValueAsListOfDefs("Spellings"); @@ -1197,6 +1220,7 @@ void EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) { OS << " virtual " << R.getName() << "Attr *clone (ASTContext &C) const;\n"; OS << " virtual void printPretty(raw_ostream &OS,\n" << " const PrintingPolicy &Policy) const;\n"; + OS << " virtual const char *getSpelling() const;\n"; writeAttrAccessorDefinition(R, OS); @@ -1328,6 +1352,7 @@ void EmitClangAttrImpl(RecordKeeper &Records, raw_ostream &OS) { OS << ", getSpellingListIndex());\n}\n\n"; writePrettyPrintFunction(R, Args, OS); + writeGetSpellingFunction(R, OS); } } -- GitLab