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
This commit is contained in:
Aaron Ballman 2013-12-26 18:30:57 +00:00
parent 1cb27131cc
commit 574efb02fa
11 changed files with 78 additions and 30 deletions

View File

@ -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

View File

@ -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

View File

@ -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 {

View File

@ -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();

View File

@ -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,

View File

@ -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

View File

@ -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();
}
}

View File

@ -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

View File

@ -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();

View File

@ -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;
}

View File

@ -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);
}
}