mirror of https://github.com/microsoft/clang.git
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:
parent
1cb27131cc
commit
574efb02fa
|
@ -85,6 +85,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned getSpellingListIndex() const { return SpellingListIndex; }
|
unsigned getSpellingListIndex() const { return SpellingListIndex; }
|
||||||
|
virtual const char *getSpelling() const = 0;
|
||||||
|
|
||||||
SourceLocation getLocation() const { return Range.getBegin(); }
|
SourceLocation getLocation() const { return Range.getBegin(); }
|
||||||
SourceRange getRange() const { return Range; }
|
SourceRange getRange() const { return Range; }
|
||||||
|
@ -138,6 +139,19 @@ public:
|
||||||
|
|
||||||
#include "clang/AST/Attrs.inc"
|
#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
|
} // end namespace clang
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -166,7 +166,8 @@ public:
|
||||||
ak_nameddecl, ///< NamedDecl *
|
ak_nameddecl, ///< NamedDecl *
|
||||||
ak_nestednamespec, ///< NestedNameSpecifier *
|
ak_nestednamespec, ///< NestedNameSpecifier *
|
||||||
ak_declcontext, ///< DeclContext *
|
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
|
/// \brief Represents on argument value, which is a union discriminated
|
||||||
|
|
|
@ -6722,7 +6722,7 @@ def err_opencl_global_invalid_addr_space : Error<
|
||||||
"global variables must have a constant address space qualifier">;
|
"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_no_main : Error<"%select{function|kernel}0 cannot be called 'main'">;
|
||||||
def err_opencl_kernel_attr :
|
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
|
} // end of sema category
|
||||||
|
|
||||||
let CategoryName = "OpenMP Issue" in {
|
let CategoryName = "OpenMP Issue" in {
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
#include "clang/AST/ASTDiagnostic.h"
|
#include "clang/AST/ASTDiagnostic.h"
|
||||||
#include "clang/AST/ASTContext.h"
|
#include "clang/AST/ASTContext.h"
|
||||||
|
#include "clang/AST/Attr.h"
|
||||||
#include "clang/AST/DeclObjC.h"
|
#include "clang/AST/DeclObjC.h"
|
||||||
#include "clang/AST/DeclTemplate.h"
|
#include "clang/AST/DeclTemplate.h"
|
||||||
#include "clang/AST/ExprCXX.h"
|
#include "clang/AST/ExprCXX.h"
|
||||||
|
@ -359,6 +360,14 @@ void clang::FormatASTNodeDiagnosticArgument(
|
||||||
NeedQuotes = false;
|
NeedQuotes = false;
|
||||||
break;
|
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();
|
OS.flush();
|
||||||
|
|
|
@ -861,6 +861,7 @@ FormatDiagnostic(const char *DiagStr, const char *DiagEnd,
|
||||||
case DiagnosticsEngine::ak_nameddecl:
|
case DiagnosticsEngine::ak_nameddecl:
|
||||||
case DiagnosticsEngine::ak_nestednamespec:
|
case DiagnosticsEngine::ak_nestednamespec:
|
||||||
case DiagnosticsEngine::ak_declcontext:
|
case DiagnosticsEngine::ak_declcontext:
|
||||||
|
case DiagnosticsEngine::ak_attr:
|
||||||
getDiags()->ConvertArgToString(Kind, getRawArg(ArgNo),
|
getDiags()->ConvertArgToString(Kind, getRawArg(ArgNo),
|
||||||
Modifier, ModifierLen,
|
Modifier, ModifierLen,
|
||||||
Argument, ArgumentLen,
|
Argument, ArgumentLen,
|
||||||
|
|
|
@ -8934,7 +8934,7 @@ Sema::FinalizeDeclaration(Decl *ThisDecl) {
|
||||||
|
|
||||||
if (UsedAttr *Attr = VD->getAttr<UsedAttr>()) {
|
if (UsedAttr *Attr = VD->getAttr<UsedAttr>()) {
|
||||||
if (!Attr->isInherited() && !VD->isThisDeclarationADefinition()) {
|
if (!Attr->isInherited() && !VD->isThisDeclarationADefinition()) {
|
||||||
Diag(Attr->getLocation(), diag::warn_attribute_ignored) << "'used'";
|
Diag(Attr->getLocation(), diag::warn_attribute_ignored) << Attr;
|
||||||
VD->dropAttr<UsedAttr>();
|
VD->dropAttr<UsedAttr>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9674,7 +9674,7 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D) {
|
||||||
!(LangOpts.MicrosoftExt && FD->getLexicalDeclContext()->isRecord())) {
|
!(LangOpts.MicrosoftExt && FD->getLexicalDeclContext()->isRecord())) {
|
||||||
Diag(FD->getLocation(),
|
Diag(FD->getLocation(),
|
||||||
diag::err_attribute_can_be_applied_only_to_symbol_declaration)
|
diag::err_attribute_can_be_applied_only_to_symbol_declaration)
|
||||||
<< "dllimport";
|
<< DA;
|
||||||
FD->setInvalidDecl();
|
FD->setInvalidDecl();
|
||||||
return D;
|
return D;
|
||||||
}
|
}
|
||||||
|
@ -9687,7 +9687,7 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D) {
|
||||||
// emitted.
|
// emitted.
|
||||||
Diag(FD->getLocation(),
|
Diag(FD->getLocation(),
|
||||||
diag::warn_redeclaration_without_attribute_prev_attribute_ignored)
|
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
|
// We want to attach documentation to original Decl (which might be
|
||||||
|
|
|
@ -1557,8 +1557,8 @@ static void handleVecReturnAttr(Sema &S, Decl *D, const AttributeList &Attr) {
|
||||||
return result; // This will be returned in a register
|
return result; // This will be returned in a register
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
if (D->hasAttr<VecReturnAttr>()) {
|
if (VecReturnAttr *A = D->getAttr<VecReturnAttr>()) {
|
||||||
S.Diag(Attr.getLoc(), diag::err_repeat_attribute) << "vecreturn";
|
S.Diag(Attr.getLoc(), diag::err_repeat_attribute) << A;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4127,18 +4127,16 @@ void Sema::ProcessDeclAttributeList(Scope *S, Decl *D,
|
||||||
|
|
||||||
if (!D->hasAttr<OpenCLKernelAttr>()) {
|
if (!D->hasAttr<OpenCLKernelAttr>()) {
|
||||||
// These attributes cannot be applied to a non-kernel function.
|
// These attributes cannot be applied to a non-kernel function.
|
||||||
if (D->hasAttr<ReqdWorkGroupSizeAttr>()) {
|
if (Attr *A = D->getAttr<ReqdWorkGroupSizeAttr>()) {
|
||||||
Diag(D->getLocation(), diag::err_opencl_kernel_attr)
|
Diag(D->getLocation(), diag::err_opencl_kernel_attr) << A;
|
||||||
<< "reqd_work_group_size";
|
|
||||||
D->setInvalidDecl();
|
D->setInvalidDecl();
|
||||||
}
|
}
|
||||||
if (D->hasAttr<WorkGroupSizeHintAttr>()) {
|
if (Attr *A = D->getAttr<WorkGroupSizeHintAttr>()) {
|
||||||
Diag(D->getLocation(), diag::err_opencl_kernel_attr)
|
Diag(D->getLocation(), diag::err_opencl_kernel_attr) << A;
|
||||||
<< "work_group_size_hint";
|
|
||||||
D->setInvalidDecl();
|
D->setInvalidDecl();
|
||||||
}
|
}
|
||||||
if (D->hasAttr<VecTypeHintAttr>()) {
|
if (Attr *A = D->getAttr<VecTypeHintAttr>()) {
|
||||||
Diag(D->getLocation(), diag::err_opencl_kernel_attr) << "vec_type_hint";
|
Diag(D->getLocation(), diag::err_opencl_kernel_attr) << A;
|
||||||
D->setInvalidDecl();
|
D->setInvalidDecl();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@ void bar() { return 1; }
|
||||||
|
|
||||||
// CHECK-NEG: error: void function 'bar' should not return a value
|
// CHECK-NEG: error: void function 'bar' should not return a value
|
||||||
// CHECK-NEG: 1 error generated
|
// 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: error: void function 'bar' should not return a value
|
||||||
// CHECK-POS: 1 warning and 1 error generated
|
// CHECK-POS: 1 warning and 1 error generated
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
inline void __attribute__((dllexport)) foo1(){} // expected-warning{{'dllexport' attribute ignored}}
|
inline void __attribute__((dllexport)) foo1(){} // expected-warning{{'dllexport' attribute ignored}}
|
||||||
inline void __attribute__((dllimport)) foo2(){} // expected-warning{{'dllimport' 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}}
|
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}}
|
typedef int __attribute__((dllimport)) type7; // expected-warning{{'dllimport' attribute only applies to variables and functions}}
|
||||||
|
|
||||||
void __attribute__((dllimport)) foo6();
|
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
|
// PR6269
|
||||||
inline void __declspec(dllexport) foo7(){} // expected-warning{{'dllexport' attribute ignored}}
|
inline void __declspec(dllexport) foo7(){} // expected-warning{{'dllexport' attribute ignored}}
|
||||||
inline void __declspec(dllimport) foo8(){} // expected-warning{{'dllimport' 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}}
|
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}}
|
typedef int __declspec(dllimport) type2; // expected-warning{{'dllimport' attribute only applies to variables and functions}}
|
||||||
|
|
||||||
void __declspec(dllimport) foo12();
|
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__((dllimport)) foo13(); // expected-warning{{dllimport attribute ignored}}
|
||||||
void __attribute__((dllexport)) foo13();
|
void __attribute__((dllexport)) foo13();
|
||||||
|
|
|
@ -37,11 +37,11 @@ class B : public A {
|
||||||
// MSVC allows type definition in anonymous union and struct
|
// MSVC allows type definition in anonymous union and struct
|
||||||
struct A
|
struct A
|
||||||
{
|
{
|
||||||
union
|
union
|
||||||
{
|
{
|
||||||
int a;
|
int a;
|
||||||
struct B // expected-warning {{types declared in an anonymous union are a Microsoft extension}}
|
struct B // expected-warning {{types declared in an anonymous union are a Microsoft extension}}
|
||||||
{
|
{
|
||||||
int c;
|
int c;
|
||||||
} d;
|
} d;
|
||||||
|
|
||||||
|
@ -63,7 +63,7 @@ struct A
|
||||||
{
|
{
|
||||||
int c2;
|
int c2;
|
||||||
} d2;
|
} d2;
|
||||||
|
|
||||||
union C2 // expected-warning {{types declared in an anonymous struct are a Microsoft extension}}
|
union C2 // expected-warning {{types declared in an anonymous struct are a Microsoft extension}}
|
||||||
{
|
{
|
||||||
int e2;
|
int e2;
|
||||||
|
@ -78,7 +78,7 @@ struct A
|
||||||
// __stdcall handling
|
// __stdcall handling
|
||||||
struct M {
|
struct M {
|
||||||
int __stdcall addP();
|
int __stdcall addP();
|
||||||
float __stdcall subtractP();
|
float __stdcall subtractP();
|
||||||
};
|
};
|
||||||
|
|
||||||
// __unaligned handling
|
// __unaligned handling
|
||||||
|
@ -90,7 +90,7 @@ template<typename T> void h1(T (__stdcall M::* const )()) { }
|
||||||
void m1() {
|
void m1() {
|
||||||
h1<int>(&M::addP);
|
h1<int>(&M::addP);
|
||||||
h1(&M::subtractP);
|
h1(&M::subtractP);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -98,7 +98,7 @@ void m1() {
|
||||||
|
|
||||||
void f(long long);
|
void f(long long);
|
||||||
void f(int);
|
void f(int);
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
// This is an ambiguous call in standard C++.
|
// This is an ambiguous call in standard C++.
|
||||||
|
@ -126,7 +126,7 @@ __declspec(dllimport) void f(void) { }
|
||||||
void f2(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 {
|
namespace rdar14250378 {
|
||||||
class Bar {};
|
class Bar {};
|
||||||
|
|
||||||
namespace NyNamespace {
|
namespace NyNamespace {
|
||||||
class Foo {
|
class Foo {
|
||||||
public:
|
public:
|
||||||
Bar* EnsureBar();
|
Bar* EnsureBar();
|
||||||
};
|
};
|
||||||
|
|
||||||
class Baz : public Foo {
|
class Baz : public Foo {
|
||||||
public:
|
public:
|
||||||
friend class Bar;
|
friend class Bar;
|
||||||
};
|
};
|
||||||
|
|
||||||
Bar* Foo::EnsureBar() {
|
Bar* Foo::EnsureBar() {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -954,6 +954,29 @@ static void writeAvailabilityValue(raw_ostream &OS) {
|
||||||
<< " 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,
|
static void writePrettyPrintFunction(Record &R, std::vector<Argument*> &Args,
|
||||||
raw_ostream &OS) {
|
raw_ostream &OS) {
|
||||||
std::vector<Record*> Spellings = R.getValueAsListOfDefs("Spellings");
|
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 " << R.getName() << "Attr *clone (ASTContext &C) const;\n";
|
||||||
OS << " virtual void printPretty(raw_ostream &OS,\n"
|
OS << " virtual void printPretty(raw_ostream &OS,\n"
|
||||||
<< " const PrintingPolicy &Policy) const;\n";
|
<< " const PrintingPolicy &Policy) const;\n";
|
||||||
|
OS << " virtual const char *getSpelling() const;\n";
|
||||||
|
|
||||||
writeAttrAccessorDefinition(R, OS);
|
writeAttrAccessorDefinition(R, OS);
|
||||||
|
|
||||||
|
@ -1328,6 +1352,7 @@ void EmitClangAttrImpl(RecordKeeper &Records, raw_ostream &OS) {
|
||||||
OS << ", getSpellingListIndex());\n}\n\n";
|
OS << ", getSpellingListIndex());\n}\n\n";
|
||||||
|
|
||||||
writePrettyPrintFunction(R, Args, OS);
|
writePrettyPrintFunction(R, Args, OS);
|
||||||
|
writeGetSpellingFunction(R, OS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue