From: Aaron Ballman Date: Thu, 26 Dec 2013 18:30:57 +0000 (+0000) Subject: Teach the diagnostics engine about the Attr type to make reporting on semantic attrib... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=574efb02fa1955f58bb0f9c7b4594cbbd972da45;p=clang 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 --- diff --git a/include/clang/AST/Attr.h b/include/clang/AST/Attr.h index d5dc537baf..61130b5dc1 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(At), + DiagnosticsEngine::ak_attr); + return DB; +} + +inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD, + const Attr *At) { + PD.AddTaggedVal(reinterpret_cast(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 2b0b3f9b28..97f2e80244 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 + ak_qualtype_pair, ///< pair + 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 54a4159ee6..c3ac6fbd78 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 7f7221fc6e..f3c2b224e1 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(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 4a6f070af7..eaae388fd8 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 9ed9510a65..fd576f3d5a 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -8934,7 +8934,7 @@ Sema::FinalizeDeclaration(Decl *ThisDecl) { if (UsedAttr *Attr = VD->getAttr()) { if (!Attr->isInherited() && !VD->isThisDeclarationADefinition()) { - Diag(Attr->getLocation(), diag::warn_attribute_ignored) << "'used'"; + Diag(Attr->getLocation(), diag::warn_attribute_ignored) << Attr; VD->dropAttr(); } } @@ -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 26988b2326..56e8725ab6 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()) { - S.Diag(Attr.getLoc(), diag::err_repeat_attribute) << "vecreturn"; + if (VecReturnAttr *A = D->getAttr()) { + S.Diag(Attr.getLoc(), diag::err_repeat_attribute) << A; return; } @@ -4127,18 +4127,16 @@ void Sema::ProcessDeclAttributeList(Scope *S, Decl *D, if (!D->hasAttr()) { // These attributes cannot be applied to a non-kernel function. - if (D->hasAttr()) { - Diag(D->getLocation(), diag::err_opencl_kernel_attr) - << "reqd_work_group_size"; + if (Attr *A = D->getAttr()) { + Diag(D->getLocation(), diag::err_opencl_kernel_attr) << A; D->setInvalidDecl(); } - if (D->hasAttr()) { - Diag(D->getLocation(), diag::err_opencl_kernel_attr) - << "work_group_size_hint"; + if (Attr *A = D->getAttr()) { + Diag(D->getLocation(), diag::err_opencl_kernel_attr) << A; D->setInvalidDecl(); } - if (D->hasAttr()) { - Diag(D->getLocation(), diag::err_opencl_kernel_attr) << "vec_type_hint"; + if (Attr *A = D->getAttr()) { + 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 127989b0ed..1e4689fba0 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 198c25f90c..e93507846e 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 5c51331500..32b8adb5df 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 void h1(T (__stdcall M::* const )()) { } void m1() { h1(&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 d32f3a61e8..ef753946da 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 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 &Args, raw_ostream &OS) { std::vector 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); } }