mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-11-30 09:01:19 +00:00
Fix ast print of variables with attributes
Previously clang AST prints the following declaration: int fun_var_unused() { int x __attribute__((unused)) = 0; return x; } and int __declspec(thread) x = 0; as: int fun_var_unused() { int x = 0 __attribute__((unused)); return x; } and int x = __declspec(thread) 0; which is rejected by C/C++ parser. This patch modifies the logic to print old C attributes for variables as: int __attribute__((unused)) x = 0; and the __declspec case as: int __declspec(thread) x = 0; Fixes: https://github.com/llvm/llvm-project/issues/59973 Previous version: D141714. Differential Revision:https://reviews.llvm.org/D141714
This commit is contained in:
parent
04224d1ae7
commit
46f3ade508
@ -300,10 +300,13 @@ class Spelling<string name, string variety, int version = 1> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class GNU<string name> : Spelling<name, "GNU">;
|
class GNU<string name> : Spelling<name, "GNU">;
|
||||||
class Declspec<string name> : Spelling<name, "Declspec">;
|
class Declspec<string name> : Spelling<name, "Declspec"> {
|
||||||
|
bit PrintOnLeft = 1;
|
||||||
|
}
|
||||||
class Microsoft<string name> : Spelling<name, "Microsoft">;
|
class Microsoft<string name> : Spelling<name, "Microsoft">;
|
||||||
class CXX11<string namespace, string name, int version = 1>
|
class CXX11<string namespace, string name, int version = 1>
|
||||||
: Spelling<name, "CXX11", version> {
|
: Spelling<name, "CXX11", version> {
|
||||||
|
bit CanPrintOnLeft = 0;
|
||||||
string Namespace = namespace;
|
string Namespace = namespace;
|
||||||
}
|
}
|
||||||
class C23<string namespace, string name, int version = 1>
|
class C23<string namespace, string name, int version = 1>
|
||||||
@ -559,6 +562,12 @@ class AttrSubjectMatcherAggregateRule<AttrSubject subject> {
|
|||||||
def SubjectMatcherForNamed : AttrSubjectMatcherAggregateRule<Named>;
|
def SubjectMatcherForNamed : AttrSubjectMatcherAggregateRule<Named>;
|
||||||
|
|
||||||
class Attr {
|
class Attr {
|
||||||
|
// Specifies that when printed, this attribute is meaningful on the
|
||||||
|
// 'left side' of the declaration.
|
||||||
|
bit CanPrintOnLeft = 1;
|
||||||
|
// Specifies that when printed, this attribute is required to be printed on
|
||||||
|
// the 'left side' of the declaration.
|
||||||
|
bit PrintOnLeft = 0;
|
||||||
// The various ways in which an attribute can be spelled in source
|
// The various ways in which an attribute can be spelled in source
|
||||||
list<Spelling> Spellings;
|
list<Spelling> Spellings;
|
||||||
// The things to which an attribute can appertain
|
// The things to which an attribute can appertain
|
||||||
@ -892,6 +901,7 @@ def AVRSignal : InheritableAttr, TargetSpecificAttr<TargetAVR> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
def AsmLabel : InheritableAttr {
|
def AsmLabel : InheritableAttr {
|
||||||
|
let CanPrintOnLeft = 0;
|
||||||
let Spellings = [CustomKeyword<"asm">, CustomKeyword<"__asm__">];
|
let Spellings = [CustomKeyword<"asm">, CustomKeyword<"__asm__">];
|
||||||
let Args = [
|
let Args = [
|
||||||
// Label specifies the mangled name for the decl.
|
// Label specifies the mangled name for the decl.
|
||||||
@ -1434,6 +1444,7 @@ def AllocSize : InheritableAttr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
def EnableIf : InheritableAttr {
|
def EnableIf : InheritableAttr {
|
||||||
|
let CanPrintOnLeft = 0;
|
||||||
// Does not have a [[]] spelling because this attribute requires the ability
|
// Does not have a [[]] spelling because this attribute requires the ability
|
||||||
// to parse function arguments but the attribute is not written in the type
|
// to parse function arguments but the attribute is not written in the type
|
||||||
// position.
|
// position.
|
||||||
@ -2920,6 +2931,7 @@ def Unavailable : InheritableAttr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
def DiagnoseIf : InheritableAttr {
|
def DiagnoseIf : InheritableAttr {
|
||||||
|
let CanPrintOnLeft = 0;
|
||||||
// Does not have a [[]] spelling because this attribute requires the ability
|
// Does not have a [[]] spelling because this attribute requires the ability
|
||||||
// to parse function arguments but the attribute is not written in the type
|
// to parse function arguments but the attribute is not written in the type
|
||||||
// position.
|
// position.
|
||||||
|
@ -30,6 +30,16 @@ clang_tablegen(AttrList.inc -gen-clang-attr-list
|
|||||||
SOURCE Attr.td
|
SOURCE Attr.td
|
||||||
TARGET ClangAttrList)
|
TARGET ClangAttrList)
|
||||||
|
|
||||||
|
clang_tablegen(AttrLeftSideCanPrintList.inc -gen-clang-attr-can-print-left-list
|
||||||
|
-I ${CMAKE_CURRENT_SOURCE_DIR}/../../
|
||||||
|
SOURCE Attr.td
|
||||||
|
TARGET ClangAttrCanPrintLeftList)
|
||||||
|
|
||||||
|
clang_tablegen(AttrLeftSideMustPrintList.inc -gen-clang-attr-must-print-left-list
|
||||||
|
-I ${CMAKE_CURRENT_SOURCE_DIR}/../../
|
||||||
|
SOURCE Attr.td
|
||||||
|
TARGET ClangAttrMustPrintLeftList)
|
||||||
|
|
||||||
clang_tablegen(AttrSubMatchRulesList.inc -gen-clang-attr-subject-match-rule-list
|
clang_tablegen(AttrSubMatchRulesList.inc -gen-clang-attr-subject-match-rule-list
|
||||||
-I ${CMAKE_CURRENT_SOURCE_DIR}/../../
|
-I ${CMAKE_CURRENT_SOURCE_DIR}/../../
|
||||||
SOURCE Attr.td
|
SOURCE Attr.td
|
||||||
|
@ -49,6 +49,18 @@ namespace {
|
|||||||
|
|
||||||
void PrintObjCTypeParams(ObjCTypeParamList *Params);
|
void PrintObjCTypeParams(ObjCTypeParamList *Params);
|
||||||
|
|
||||||
|
enum class AttrPrintLoc {
|
||||||
|
None = 0,
|
||||||
|
Left = 1,
|
||||||
|
Right = 2,
|
||||||
|
Any = Left | Right,
|
||||||
|
|
||||||
|
LLVM_MARK_AS_BITMASK_ENUM(/*DefaultValue=*/Any)
|
||||||
|
};
|
||||||
|
|
||||||
|
void prettyPrintAttributes(Decl *D, raw_ostream &out,
|
||||||
|
AttrPrintLoc loc = AttrPrintLoc::Any);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DeclPrinter(raw_ostream &Out, const PrintingPolicy &Policy,
|
DeclPrinter(raw_ostream &Out, const PrintingPolicy &Policy,
|
||||||
const ASTContext &Context, unsigned Indentation = 0,
|
const ASTContext &Context, unsigned Indentation = 0,
|
||||||
@ -117,7 +129,11 @@ namespace {
|
|||||||
const TemplateParameterList *Params);
|
const TemplateParameterList *Params);
|
||||||
void printTemplateArguments(llvm::ArrayRef<TemplateArgumentLoc> Args,
|
void printTemplateArguments(llvm::ArrayRef<TemplateArgumentLoc> Args,
|
||||||
const TemplateParameterList *Params);
|
const TemplateParameterList *Params);
|
||||||
void prettyPrintAttributes(Decl *D);
|
|
||||||
|
inline void prettyPrintAttributes(Decl *D) {
|
||||||
|
prettyPrintAttributes(D, Out);
|
||||||
|
}
|
||||||
|
|
||||||
void prettyPrintPragmas(Decl *D);
|
void prettyPrintPragmas(Decl *D);
|
||||||
void printDeclType(QualType T, StringRef DeclName, bool Pack = false);
|
void printDeclType(QualType T, StringRef DeclName, bool Pack = false);
|
||||||
};
|
};
|
||||||
@ -234,7 +250,40 @@ raw_ostream& DeclPrinter::Indent(unsigned Indentation) {
|
|||||||
return Out;
|
return Out;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeclPrinter::prettyPrintAttributes(Decl *D) {
|
static bool canPrintOnLeftSide(attr::Kind kind) {
|
||||||
|
switch (kind) {
|
||||||
|
#include "clang/Basic/AttrLeftSideCanPrintList.inc"
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool canPrintOnLeftSide(const Attr *A) {
|
||||||
|
if (A->isStandardAttributeSyntax())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return canPrintOnLeftSide(A->getKind());
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool mustPrintOnLeftSide(attr::Kind kind) {
|
||||||
|
switch (kind) {
|
||||||
|
#include "clang/Basic/AttrLeftSideMustPrintList.inc"
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool mustPrintOnLeftSide(const Attr *A) {
|
||||||
|
if (A->isDeclspecAttribute())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return mustPrintOnLeftSide(A->getKind());
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeclPrinter::prettyPrintAttributes(Decl *D, llvm::raw_ostream &Out,
|
||||||
|
AttrPrintLoc Loc) {
|
||||||
if (Policy.PolishForDeclaration)
|
if (Policy.PolishForDeclaration)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -243,15 +292,32 @@ void DeclPrinter::prettyPrintAttributes(Decl *D) {
|
|||||||
for (auto *A : Attrs) {
|
for (auto *A : Attrs) {
|
||||||
if (A->isInherited() || A->isImplicit())
|
if (A->isInherited() || A->isImplicit())
|
||||||
continue;
|
continue;
|
||||||
switch (A->getKind()) {
|
|
||||||
#define ATTR(X)
|
AttrPrintLoc AttrLoc = AttrPrintLoc::Right;
|
||||||
#define PRAGMA_SPELLING_ATTR(X) case attr::X:
|
if (mustPrintOnLeftSide(A)) {
|
||||||
#include "clang/Basic/AttrList.inc"
|
// If we must always print on left side (e.g. declspec), then mark as
|
||||||
break;
|
// so.
|
||||||
default:
|
AttrLoc = AttrPrintLoc::Left;
|
||||||
A->printPretty(Out, Policy);
|
} else if (canPrintOnLeftSide(A)) {
|
||||||
break;
|
// For functions with body defined we print the attributes on the left
|
||||||
|
// side so that GCC accept our dumps as well.
|
||||||
|
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D);
|
||||||
|
FD && FD->isThisDeclarationADefinition())
|
||||||
|
// In case Decl is a function with a body, then attrs should be print
|
||||||
|
// on the left side.
|
||||||
|
AttrLoc = AttrPrintLoc::Left;
|
||||||
|
|
||||||
|
// In case it is a variable declaration with a ctor, then allow
|
||||||
|
// printing on the left side for readbility.
|
||||||
|
else if (const VarDecl *VD = dyn_cast<VarDecl>(D);
|
||||||
|
VD && VD->getInit() &&
|
||||||
|
VD->getInitStyle() == VarDecl::CallInit)
|
||||||
|
AttrLoc = AttrPrintLoc::Left;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Only print the side matches the user requested.
|
||||||
|
if ((Loc & AttrLoc) != AttrPrintLoc::None)
|
||||||
|
A->printPretty(Out, Policy);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -613,6 +679,22 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
|
|||||||
printTemplateParameters(D->getTemplateParameterList(I));
|
printTemplateParameters(D->getTemplateParameterList(I));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string LeftsideAttrs;
|
||||||
|
llvm::raw_string_ostream LSAS(LeftsideAttrs);
|
||||||
|
|
||||||
|
prettyPrintAttributes(D, LSAS, AttrPrintLoc::Left);
|
||||||
|
|
||||||
|
// prettyPrintAttributes print a space on left side of the attribute.
|
||||||
|
if (LeftsideAttrs[0] == ' ') {
|
||||||
|
// Skip the space prettyPrintAttributes generated.
|
||||||
|
LeftsideAttrs.erase(0, LeftsideAttrs.find_first_not_of(' '));
|
||||||
|
|
||||||
|
// Add a single space between the attribute and the Decl name.
|
||||||
|
LSAS << ' ';
|
||||||
|
}
|
||||||
|
|
||||||
|
Out << LeftsideAttrs;
|
||||||
|
|
||||||
CXXConstructorDecl *CDecl = dyn_cast<CXXConstructorDecl>(D);
|
CXXConstructorDecl *CDecl = dyn_cast<CXXConstructorDecl>(D);
|
||||||
CXXConversionDecl *ConversionDecl = dyn_cast<CXXConversionDecl>(D);
|
CXXConversionDecl *ConversionDecl = dyn_cast<CXXConversionDecl>(D);
|
||||||
CXXDeductionGuideDecl *GuideDecl = dyn_cast<CXXDeductionGuideDecl>(D);
|
CXXDeductionGuideDecl *GuideDecl = dyn_cast<CXXDeductionGuideDecl>(D);
|
||||||
@ -774,7 +856,7 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
|
|||||||
Ty.print(Out, Policy, Proto);
|
Ty.print(Out, Policy, Proto);
|
||||||
}
|
}
|
||||||
|
|
||||||
prettyPrintAttributes(D);
|
prettyPrintAttributes(D, Out, AttrPrintLoc::Right);
|
||||||
|
|
||||||
if (D->isPure())
|
if (D->isPure())
|
||||||
Out << " = 0";
|
Out << " = 0";
|
||||||
@ -867,6 +949,23 @@ void DeclPrinter::VisitLabelDecl(LabelDecl *D) {
|
|||||||
void DeclPrinter::VisitVarDecl(VarDecl *D) {
|
void DeclPrinter::VisitVarDecl(VarDecl *D) {
|
||||||
prettyPrintPragmas(D);
|
prettyPrintPragmas(D);
|
||||||
|
|
||||||
|
std::string LeftSide;
|
||||||
|
llvm::raw_string_ostream LeftSideStream(LeftSide);
|
||||||
|
|
||||||
|
// Print attributes that should be placed on the left, such as __declspec.
|
||||||
|
prettyPrintAttributes(D, LeftSideStream, AttrPrintLoc::Left);
|
||||||
|
|
||||||
|
// prettyPrintAttributes print a space on left side of the attribute.
|
||||||
|
if (LeftSide[0] == ' ') {
|
||||||
|
// Skip the space prettyPrintAttributes generated.
|
||||||
|
LeftSide.erase(0, LeftSide.find_first_not_of(' '));
|
||||||
|
|
||||||
|
// Add a single space between the attribute and the Decl name.
|
||||||
|
LeftSideStream << ' ';
|
||||||
|
}
|
||||||
|
|
||||||
|
Out << LeftSide;
|
||||||
|
|
||||||
QualType T = D->getTypeSourceInfo()
|
QualType T = D->getTypeSourceInfo()
|
||||||
? D->getTypeSourceInfo()->getType()
|
? D->getTypeSourceInfo()->getType()
|
||||||
: D->getASTContext().getUnqualifiedObjCPointerType(D->getType());
|
: D->getASTContext().getUnqualifiedObjCPointerType(D->getType());
|
||||||
@ -899,10 +998,19 @@ void DeclPrinter::VisitVarDecl(VarDecl *D) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
printDeclType(T, (isa<ParmVarDecl>(D) && Policy.CleanUglifiedParameters &&
|
StringRef Name;
|
||||||
D->getIdentifier())
|
|
||||||
? D->getIdentifier()->deuglifiedName()
|
Name = (isa<ParmVarDecl>(D) && Policy.CleanUglifiedParameters &&
|
||||||
: D->getName());
|
D->getIdentifier())
|
||||||
|
? D->getIdentifier()->deuglifiedName()
|
||||||
|
: D->getName();
|
||||||
|
|
||||||
|
printDeclType(T, Name);
|
||||||
|
|
||||||
|
// Print the attributes that should be placed right before the end of the
|
||||||
|
// decl.
|
||||||
|
prettyPrintAttributes(D, Out, AttrPrintLoc::Right);
|
||||||
|
|
||||||
Expr *Init = D->getInit();
|
Expr *Init = D->getInit();
|
||||||
if (!Policy.SuppressInitializers && Init) {
|
if (!Policy.SuppressInitializers && Init) {
|
||||||
bool ImplicitInit = false;
|
bool ImplicitInit = false;
|
||||||
@ -931,7 +1039,6 @@ void DeclPrinter::VisitVarDecl(VarDecl *D) {
|
|||||||
Out << ")";
|
Out << ")";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
prettyPrintAttributes(D);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeclPrinter::VisitParmVarDecl(ParmVarDecl *D) {
|
void DeclPrinter::VisitParmVarDecl(ParmVarDecl *D) {
|
||||||
|
17
clang/test/AST/ast-print-attr-knr.c
Normal file
17
clang/test/AST/ast-print-attr-knr.c
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
// This file contain tests for attribute arguments on K&R functions.
|
||||||
|
|
||||||
|
// RUN: %clang_cc1 -ast-print -x c -std=c89 -fms-extensions %s -o - | FileCheck %s
|
||||||
|
|
||||||
|
// CHECK: int knr(i)
|
||||||
|
// CHECK-NEXT: int i __attribute__((unused));
|
||||||
|
// CHECK-NEXT: {
|
||||||
|
// CHECK-NEXT: return 0;
|
||||||
|
// CHECK-NEXT: }
|
||||||
|
int knr(i) int i __attribute__((unused)); { return 0; }
|
||||||
|
|
||||||
|
// CHECK: __attribute__((unused)) int knr2(i)
|
||||||
|
// CHECK-NEXT: int i;
|
||||||
|
// CHECK-NEXT: {
|
||||||
|
// CHECK-NEXT: return 0;
|
||||||
|
// CHECK-NEXT: }
|
||||||
|
__attribute__((unused)) int knr2(i) int i; { return 0; }
|
@ -32,3 +32,9 @@ int *fun_returns() __attribute__((ownership_returns(fun_returns)));
|
|||||||
|
|
||||||
// CHECK: void fun_holds(int *a) __attribute__((ownership_holds(fun_holds, 1)));
|
// CHECK: void fun_holds(int *a) __attribute__((ownership_holds(fun_holds, 1)));
|
||||||
void fun_holds(int *a) __attribute__((ownership_holds(fun_holds, 1)));
|
void fun_holds(int *a) __attribute__((ownership_holds(fun_holds, 1)));
|
||||||
|
|
||||||
|
// CHECK: int fun_var_unused() {
|
||||||
|
// CHECK-NEXT: int x __attribute__((unused)) = 0;
|
||||||
|
// CHECK-NEXT: return x;
|
||||||
|
// CHECK-NEXT: }
|
||||||
|
int fun_var_unused() { int x __attribute__((unused)) = 0; return x; }
|
||||||
|
@ -95,7 +95,7 @@ struct DefMethodsWithoutBody {
|
|||||||
// CHECK-NEXT: DefMethodsWithoutBody() = default;
|
// CHECK-NEXT: DefMethodsWithoutBody() = default;
|
||||||
~DefMethodsWithoutBody() = default;
|
~DefMethodsWithoutBody() = default;
|
||||||
|
|
||||||
// CHECK-NEXT: void m1() __attribute__((alias("X")));
|
// CHECK-NEXT: __attribute__((alias("X"))) void m1();
|
||||||
void m1() __attribute__((alias("X")));
|
void m1() __attribute__((alias("X")));
|
||||||
|
|
||||||
// CHECK-NEXT: };
|
// CHECK-NEXT: };
|
||||||
|
@ -93,7 +93,7 @@ void test_templates(int *List, int Length) {
|
|||||||
#ifdef MS_EXT
|
#ifdef MS_EXT
|
||||||
#pragma init_seg(compiler)
|
#pragma init_seg(compiler)
|
||||||
// MS-EXT: #pragma init_seg (.CRT$XCC){{$}}
|
// MS-EXT: #pragma init_seg (.CRT$XCC){{$}}
|
||||||
// MS-EXT-NEXT: int x = 3 __declspec(thread);
|
// MS-EXT-NEXT: __declspec(thread) int x = 3;
|
||||||
int __declspec(thread) x = 3;
|
__declspec(thread) int x = 3;
|
||||||
#endif //MS_EXT
|
#endif //MS_EXT
|
||||||
|
|
||||||
|
@ -78,7 +78,7 @@ void testBlockWithCaptureByReference() {
|
|||||||
// CHECK-NEXT: 1: 5
|
// CHECK-NEXT: 1: 5
|
||||||
// WARNINGS-NEXT: 2: [B1.1] (CXXConstructExpr, StructWithCopyConstructor)
|
// WARNINGS-NEXT: 2: [B1.1] (CXXConstructExpr, StructWithCopyConstructor)
|
||||||
// ANALYZER-NEXT: 2: [B1.1] (CXXConstructExpr, [B1.3], StructWithCopyConstructor)
|
// ANALYZER-NEXT: 2: [B1.1] (CXXConstructExpr, [B1.3], StructWithCopyConstructor)
|
||||||
// CHECK-NEXT: 3: StructWithCopyConstructor s(5) __attribute__((blocks("byref")));
|
// CHECK-NEXT: 3: __attribute__((blocks("byref"))) StructWithCopyConstructor s(5);
|
||||||
// CHECK-NEXT: 4: ^{ }
|
// CHECK-NEXT: 4: ^{ }
|
||||||
// CHECK-NEXT: 5: (void)([B1.4]) (CStyleCastExpr, ToVoid, void)
|
// CHECK-NEXT: 5: (void)([B1.4]) (CStyleCastExpr, ToVoid, void)
|
||||||
// CHECK-NEXT: Preds (1): B2
|
// CHECK-NEXT: Preds (1): B2
|
||||||
|
@ -67,41 +67,41 @@ int lambda_outer() {
|
|||||||
}
|
}
|
||||||
#pragma omp end assumes
|
#pragma omp end assumes
|
||||||
|
|
||||||
// AST: void foo() __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp"))) {
|
// AST: __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp"))) void foo() {
|
||||||
// AST-NEXT: }
|
// AST-NEXT: }
|
||||||
// AST-NEXT: class BAR {
|
// AST-NEXT: class BAR {
|
||||||
// AST-NEXT: public:
|
// AST-NEXT: public:
|
||||||
// AST-NEXT: BAR() __attribute__((assume("ompx_range_bar_only"))) __attribute__((assume("ompx_range_bar_only_2"))) __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp"))) {
|
// AST-NEXT: __attribute__((assume("ompx_range_bar_only"))) __attribute__((assume("ompx_range_bar_only_2"))) __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp"))) BAR() {
|
||||||
// AST-NEXT: }
|
// AST-NEXT: }
|
||||||
// AST-NEXT: void bar1() __attribute__((assume("ompx_range_bar_only"))) __attribute__((assume("ompx_range_bar_only_2"))) __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp"))) {
|
// AST-NEXT: __attribute__((assume("ompx_range_bar_only"))) __attribute__((assume("ompx_range_bar_only_2"))) __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp"))) void bar1() {
|
||||||
// AST-NEXT: }
|
// AST-NEXT: }
|
||||||
// AST-NEXT: static void bar2() __attribute__((assume("ompx_range_bar_only"))) __attribute__((assume("ompx_range_bar_only_2"))) __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp"))) {
|
// AST-NEXT: __attribute__((assume("ompx_range_bar_only"))) __attribute__((assume("ompx_range_bar_only_2"))) __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp"))) static void bar2() {
|
||||||
// AST-NEXT: }
|
// AST-NEXT: }
|
||||||
// AST-NEXT: };
|
// AST-NEXT: };
|
||||||
// AST-NEXT: void bar() __attribute__((assume("ompx_range_bar_only"))) __attribute__((assume("ompx_range_bar_only_2"))) __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp"))) {
|
// AST-NEXT: __attribute__((assume("ompx_range_bar_only"))) __attribute__((assume("ompx_range_bar_only_2"))) __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp"))) void bar() {
|
||||||
// AST-NEXT: BAR b;
|
// AST-NEXT: BAR b;
|
||||||
// AST-NEXT: }
|
// AST-NEXT: }
|
||||||
// AST-NEXT: void baz() __attribute__((assume("ompx_1234"))) __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp")));
|
// AST-NEXT: void baz() __attribute__((assume("ompx_1234"))) __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp")));
|
||||||
// AST-NEXT: template <typename T> class BAZ {
|
// AST-NEXT: template <typename T> class BAZ {
|
||||||
// AST-NEXT: public:
|
// AST-NEXT: public:
|
||||||
// AST-NEXT: BAZ<T>() __attribute__((assume("ompx_1234"))) __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp"))) {
|
// AST-NEXT: __attribute__((assume("ompx_1234"))) __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp"))) BAZ<T>() {
|
||||||
// AST-NEXT: }
|
// AST-NEXT: }
|
||||||
// AST-NEXT: void baz1() __attribute__((assume("ompx_1234"))) __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp"))) {
|
// AST-NEXT: __attribute__((assume("ompx_1234"))) __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp"))) void baz1() {
|
||||||
// AST-NEXT: }
|
// AST-NEXT: }
|
||||||
// AST-NEXT: static void baz2() __attribute__((assume("ompx_1234"))) __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp"))) {
|
// AST-NEXT: __attribute__((assume("ompx_1234"))) __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp"))) static void baz2() {
|
||||||
// AST-NEXT: }
|
// AST-NEXT: }
|
||||||
// AST-NEXT: };
|
// AST-NEXT: };
|
||||||
// AST-NEXT: template<> class BAZ<float> {
|
// AST-NEXT: template<> class BAZ<float> {
|
||||||
// AST-NEXT: public:
|
// AST-NEXT: public:
|
||||||
// AST-NEXT: BAZ() __attribute__((assume("ompx_1234"))) __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp"))) __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp"))) {
|
// AST-NEXT: __attribute__((assume("ompx_1234"))) __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp"))) __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp"))) BAZ() {
|
||||||
// AST-NEXT: }
|
// AST-NEXT: }
|
||||||
// AST-NEXT: void baz1() __attribute__((assume("ompx_1234"))) __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp"))) __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp")));
|
// AST-NEXT: void baz1() __attribute__((assume("ompx_1234"))) __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp"))) __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp")));
|
||||||
// AST-NEXT: static void baz2() __attribute__((assume("ompx_1234"))) __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp"))) __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp")));
|
// AST-NEXT: static void baz2() __attribute__((assume("ompx_1234"))) __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp"))) __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp")));
|
||||||
// AST-NEXT: };
|
// AST-NEXT: };
|
||||||
// AST-NEXT: void baz() __attribute__((assume("ompx_1234"))) __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp"))) {
|
// AST-NEXT: __attribute__((assume("ompx_1234"))) __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp"))) void baz() {
|
||||||
// AST-NEXT: BAZ<float> b;
|
// AST-NEXT: BAZ<float> b;
|
||||||
// AST-NEXT: }
|
// AST-NEXT: }
|
||||||
// AST-NEXT: int lambda_outer() __attribute__((assume("ompx_lambda_assumption"))) __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp"))) {
|
// AST-NEXT: __attribute__((assume("ompx_lambda_assumption"))) __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp"))) int lambda_outer() {
|
||||||
// AST-NEXT: auto lambda_inner = []() {
|
// AST-NEXT: auto lambda_inner = []() {
|
||||||
// AST-NEXT: return 42;
|
// AST-NEXT: return 42;
|
||||||
// AST-NEXT: };
|
// AST-NEXT: };
|
||||||
|
@ -37,8 +37,8 @@ void baz() {
|
|||||||
}
|
}
|
||||||
#pragma omp end assumes
|
#pragma omp end assumes
|
||||||
|
|
||||||
// CHECK: void foo() __attribute__((assume("omp_no_openmp_routines"))) __attribute__((assume("omp_no_openmp")))
|
// CHECK: __attribute__((assume("omp_no_openmp_routines"))) __attribute__((assume("omp_no_openmp"))) void foo()
|
||||||
// CHECK: void bar() __attribute__((assume("ompx_range_bar_only"))) __attribute__((assume("ompx_range_bar_only_2"))) __attribute__((assume("omp_no_openmp_routines"))) __attribute__((assume("omp_no_openmp")))
|
// CHECK: __attribute__((assume("ompx_range_bar_only"))) __attribute__((assume("ompx_range_bar_only_2"))) __attribute__((assume("omp_no_openmp_routines"))) __attribute__((assume("omp_no_openmp"))) void bar()
|
||||||
// CHECK: void baz() __attribute__((assume("ompx_1234"))) __attribute__((assume("omp_no_openmp_routines"))) __attribute__((assume("omp_no_openmp")))
|
// CHECK: __attribute__((assume("ompx_1234"))) __attribute__((assume("omp_no_openmp_routines"))) __attribute__((assume("omp_no_openmp"))) void baz()
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -17,7 +17,7 @@ template <typename T>
|
|||||||
struct S {
|
struct S {
|
||||||
int a;
|
int a;
|
||||||
// CHECK: template <typename T> struct S {
|
// CHECK: template <typename T> struct S {
|
||||||
// CHECK: void foo() __attribute__((assume("ompx_global_assumption"))) {
|
// CHECK: __attribute__((assume("ompx_global_assumption"))) void foo() {
|
||||||
void foo() {
|
void foo() {
|
||||||
#pragma omp parallel
|
#pragma omp parallel
|
||||||
{}
|
{}
|
||||||
@ -25,15 +25,15 @@ struct S {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// CHECK: template<> struct S<int> {
|
// CHECK: template<> struct S<int> {
|
||||||
// CHECK: void foo() __attribute__((assume("ompx_global_assumption"))) {
|
// CHECK: __attribute__((assume("ompx_global_assumption"))) void foo() {
|
||||||
|
|
||||||
#pragma omp begin assumes no_openmp
|
#pragma omp begin assumes no_openmp
|
||||||
// CHECK: void S_with_assumes_no_call() __attribute__((assume("omp_no_openmp"))) __attribute__((assume("ompx_global_assumption"))) {
|
// CHECK: __attribute__((assume("omp_no_openmp"))) __attribute__((assume("ompx_global_assumption"))) void S_with_assumes_no_call() {
|
||||||
void S_with_assumes_no_call() {
|
void S_with_assumes_no_call() {
|
||||||
S<int> s;
|
S<int> s;
|
||||||
s.a = 0;
|
s.a = 0;
|
||||||
}
|
}
|
||||||
// CHECK: void S_with_assumes_call() __attribute__((assume("omp_no_openmp"))) __attribute__((assume("ompx_global_assumption"))) {
|
// CHECK: __attribute__((assume("omp_no_openmp"))) __attribute__((assume("ompx_global_assumption"))) void S_with_assumes_call() {
|
||||||
void S_with_assumes_call() {
|
void S_with_assumes_call() {
|
||||||
S<int> s;
|
S<int> s;
|
||||||
s.a = 0;
|
s.a = 0;
|
||||||
@ -42,7 +42,7 @@ void S_with_assumes_call() {
|
|||||||
}
|
}
|
||||||
#pragma omp end assumes
|
#pragma omp end assumes
|
||||||
|
|
||||||
// CHECK: void S_without_assumes() __attribute__((assume("ompx_global_assumption"))) {
|
// CHECK: __attribute__((assume("ompx_global_assumption"))) void S_without_assumes() {
|
||||||
void S_without_assumes() {
|
void S_without_assumes() {
|
||||||
S<int> s;
|
S<int> s;
|
||||||
s.foo();
|
s.foo();
|
||||||
@ -54,7 +54,7 @@ void S_without_assumes() {
|
|||||||
template <typename T>
|
template <typename T>
|
||||||
struct P {
|
struct P {
|
||||||
// CHECK: template <typename T> struct P {
|
// CHECK: template <typename T> struct P {
|
||||||
// CHECK: void foo() __attribute__((assume("ompx_global_assumption"))) {
|
// CHECK: __attribute__((assume("ompx_global_assumption"))) void foo() {
|
||||||
int a;
|
int a;
|
||||||
void foo() {
|
void foo() {
|
||||||
#pragma omp parallel
|
#pragma omp parallel
|
||||||
@ -65,21 +65,21 @@ struct P {
|
|||||||
// TODO: Avoid the duplication here:
|
// TODO: Avoid the duplication here:
|
||||||
|
|
||||||
// CHECK: template<> struct P<int> {
|
// CHECK: template<> struct P<int> {
|
||||||
// CHECK: void foo() __attribute__((assume("ompx_global_assumption"))) __attribute__((assume("ompx_global_assumption"))) {
|
// CHECK: __attribute__((assume("ompx_global_assumption"))) __attribute__((assume("ompx_global_assumption"))) void foo() {
|
||||||
|
|
||||||
// CHECK: void P_without_assumes() __attribute__((assume("ompx_global_assumption"))) {
|
// CHECK: __attribute__((assume("ompx_global_assumption"))) void P_without_assumes() {
|
||||||
void P_without_assumes() {
|
void P_without_assumes() {
|
||||||
P<int> p;
|
P<int> p;
|
||||||
p.foo();
|
p.foo();
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma omp begin assumes no_openmp
|
#pragma omp begin assumes no_openmp
|
||||||
// CHECK: void P_with_assumes_no_call() __attribute__((assume("omp_no_openmp"))) __attribute__((assume("ompx_global_assumption"))) {
|
// CHECK: __attribute__((assume("omp_no_openmp"))) __attribute__((assume("ompx_global_assumption"))) void P_with_assumes_no_call() {
|
||||||
void P_with_assumes_no_call() {
|
void P_with_assumes_no_call() {
|
||||||
P<int> p;
|
P<int> p;
|
||||||
p.a = 0;
|
p.a = 0;
|
||||||
}
|
}
|
||||||
// CHECK: void P_with_assumes_call() __attribute__((assume("omp_no_openmp"))) __attribute__((assume("ompx_global_assumption"))) {
|
// CHECK: __attribute__((assume("omp_no_openmp"))) __attribute__((assume("ompx_global_assumption"))) void P_with_assumes_call() {
|
||||||
void P_with_assumes_call() {
|
void P_with_assumes_call() {
|
||||||
P<int> p;
|
P<int> p;
|
||||||
p.a = 0;
|
p.a = 0;
|
||||||
|
@ -60,11 +60,11 @@ void h(int *hp, int *hp2, int *hq, int *lin)
|
|||||||
|
|
||||||
class VV {
|
class VV {
|
||||||
// CHECK: #pragma omp declare simd uniform(this, a) linear(val(b): a)
|
// CHECK: #pragma omp declare simd uniform(this, a) linear(val(b): a)
|
||||||
// CHECK-NEXT: int add(int a, int b) __attribute__((cold)) {
|
// CHECK-NEXT: __attribute__((cold)) int add(int a, int b) {
|
||||||
// CHECK-NEXT: return a + b;
|
// CHECK-NEXT: return a + b;
|
||||||
// CHECK-NEXT: }
|
// CHECK-NEXT: }
|
||||||
#pragma omp declare simd uniform(this, a) linear(val(b): a)
|
#pragma omp declare simd uniform(this, a) linear(val(b): a)
|
||||||
int add(int a, int b) __attribute__((cold)) { return a + b; }
|
__attribute__((cold)) int add(int a, int b) { return a + b; }
|
||||||
|
|
||||||
// CHECK: #pragma omp declare simd aligned(b: 4) aligned(a) linear(ref(b): 4) linear(val(this)) linear(val(a))
|
// CHECK: #pragma omp declare simd aligned(b: 4) aligned(a) linear(ref(b): 4) linear(val(this)) linear(val(a))
|
||||||
// CHECK-NEXT: float taddpf(float *a, float *&b) {
|
// CHECK-NEXT: float taddpf(float *a, float *&b) {
|
||||||
|
@ -3,8 +3,7 @@
|
|||||||
// CHECK: int x __attribute__((aligned(4)));
|
// CHECK: int x __attribute__((aligned(4)));
|
||||||
int x __attribute__((aligned(4)));
|
int x __attribute__((aligned(4)));
|
||||||
|
|
||||||
// FIXME: Print this at a valid location for a __declspec attr.
|
// CHECK: __declspec(align(4)) int y;
|
||||||
// CHECK: int y __declspec(align(4));
|
|
||||||
__declspec(align(4)) int y;
|
__declspec(align(4)) int y;
|
||||||
|
|
||||||
// CHECK: short arr[3] __attribute__((aligned));
|
// CHECK: short arr[3] __attribute__((aligned));
|
||||||
|
@ -3,8 +3,7 @@
|
|||||||
// CHECK: int x __attribute__((aligned(4)));
|
// CHECK: int x __attribute__((aligned(4)));
|
||||||
int x __attribute__((aligned(4)));
|
int x __attribute__((aligned(4)));
|
||||||
|
|
||||||
// FIXME: Print this at a valid location for a __declspec attr.
|
// CHECK: __declspec(align(4)) int y;
|
||||||
// CHECK: int y __declspec(align(4));
|
|
||||||
__declspec(align(4)) int y;
|
__declspec(align(4)) int y;
|
||||||
|
|
||||||
// CHECK: void foo() __attribute__((const));
|
// CHECK: void foo() __attribute__((const));
|
||||||
|
@ -3,8 +3,7 @@
|
|||||||
// CHECK: int x __attribute__((aligned(4)));
|
// CHECK: int x __attribute__((aligned(4)));
|
||||||
int x __attribute__((aligned(4)));
|
int x __attribute__((aligned(4)));
|
||||||
|
|
||||||
// FIXME: Print this at a valid location for a __declspec attr.
|
// CHECK: __declspec(align(4)) int y;
|
||||||
// CHECK: int y __declspec(align(4));
|
|
||||||
__declspec(align(4)) int y;
|
__declspec(align(4)) int y;
|
||||||
|
|
||||||
// CHECK: int z {{\[}}[gnu::aligned(4)]];
|
// CHECK: int z {{\[}}[gnu::aligned(4)]];
|
||||||
@ -66,7 +65,7 @@ void f8 (void *, const char *, ...) __attribute__ ((format (printf, 2, 3)));
|
|||||||
// CHECK: int m __attribute__((aligned(4
|
// CHECK: int m __attribute__((aligned(4
|
||||||
// CHECK: int n alignas(4
|
// CHECK: int n alignas(4
|
||||||
// CHECK: int p alignas(int
|
// CHECK: int p alignas(int
|
||||||
// CHECK: static int f() __attribute__((pure))
|
// CHECK: __attribute__((pure)) static int f()
|
||||||
// CHECK: static int g() {{\[}}[gnu::pure]]
|
// CHECK: static int g() {{\[}}[gnu::pure]]
|
||||||
template <typename T> struct S {
|
template <typename T> struct S {
|
||||||
__attribute__((aligned(4))) int m;
|
__attribute__((aligned(4))) int m;
|
||||||
@ -82,7 +81,7 @@ template <typename T> struct S {
|
|||||||
|
|
||||||
// CHECK: int m __attribute__((aligned(4
|
// CHECK: int m __attribute__((aligned(4
|
||||||
// CHECK: int n alignas(4
|
// CHECK: int n alignas(4
|
||||||
// CHECK: static int f() __attribute__((pure))
|
// CHECK: __attribute__((pure)) static int f()
|
||||||
// CHECK: static int g() {{\[}}[gnu::pure]]
|
// CHECK: static int g() {{\[}}[gnu::pure]]
|
||||||
template struct S<int>;
|
template struct S<int>;
|
||||||
|
|
||||||
|
@ -3207,6 +3207,27 @@ void EmitClangAttrList(RecordKeeper &Records, raw_ostream &OS) {
|
|||||||
OS << "#undef PRAGMA_SPELLING_ATTR\n";
|
OS << "#undef PRAGMA_SPELLING_ATTR\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Emits the enumeration list for attributes.
|
||||||
|
void EmitClangAttrPrintList(const std::string &FieldName, RecordKeeper &Records,
|
||||||
|
raw_ostream &OS) {
|
||||||
|
emitSourceFileHeader(
|
||||||
|
"List of attributes that can be print on the left side of a decl", OS);
|
||||||
|
|
||||||
|
AttrClassHierarchy Hierarchy(Records);
|
||||||
|
|
||||||
|
std::vector<Record *> Attrs = Records.getAllDerivedDefinitions("Attr");
|
||||||
|
std::vector<Record *> PragmaAttrs;
|
||||||
|
for (auto *Attr : Attrs) {
|
||||||
|
if (!Attr->getValueAsBit("ASTNode"))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!Attr->getValueAsBit(FieldName))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
OS << "case attr::" << Attr->getName() << ":\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Emits the enumeration list for attributes.
|
// Emits the enumeration list for attributes.
|
||||||
void EmitClangAttrSubjectMatchRuleList(RecordKeeper &Records, raw_ostream &OS) {
|
void EmitClangAttrSubjectMatchRuleList(RecordKeeper &Records, raw_ostream &OS) {
|
||||||
emitSourceFileHeader(
|
emitSourceFileHeader(
|
||||||
|
@ -31,6 +31,8 @@ enum ActionType {
|
|||||||
GenClangAttrSubjectMatchRulesParserStringSwitches,
|
GenClangAttrSubjectMatchRulesParserStringSwitches,
|
||||||
GenClangAttrImpl,
|
GenClangAttrImpl,
|
||||||
GenClangAttrList,
|
GenClangAttrList,
|
||||||
|
GenClangAttrCanPrintLeftList,
|
||||||
|
GenClangAttrMustPrintLeftList,
|
||||||
GenClangAttrDocTable,
|
GenClangAttrDocTable,
|
||||||
GenClangAttrSubjectMatchRuleList,
|
GenClangAttrSubjectMatchRuleList,
|
||||||
GenClangAttrPCHRead,
|
GenClangAttrPCHRead,
|
||||||
@ -127,6 +129,14 @@ cl::opt<ActionType> Action(
|
|||||||
"Generate clang attribute implementations"),
|
"Generate clang attribute implementations"),
|
||||||
clEnumValN(GenClangAttrList, "gen-clang-attr-list",
|
clEnumValN(GenClangAttrList, "gen-clang-attr-list",
|
||||||
"Generate a clang attribute list"),
|
"Generate a clang attribute list"),
|
||||||
|
clEnumValN(GenClangAttrCanPrintLeftList,
|
||||||
|
"gen-clang-attr-can-print-left-list",
|
||||||
|
"Generate list of attributes that can be printed on left "
|
||||||
|
"side of a decl"),
|
||||||
|
clEnumValN(GenClangAttrMustPrintLeftList,
|
||||||
|
"gen-clang-attr-must-print-left-list",
|
||||||
|
"Generate list of attributes that must be printed on left "
|
||||||
|
"side of a decl"),
|
||||||
clEnumValN(GenClangAttrDocTable, "gen-clang-attr-doc-table",
|
clEnumValN(GenClangAttrDocTable, "gen-clang-attr-doc-table",
|
||||||
"Generate a table of attribute documentation"),
|
"Generate a table of attribute documentation"),
|
||||||
clEnumValN(GenClangAttrSubjectMatchRuleList,
|
clEnumValN(GenClangAttrSubjectMatchRuleList,
|
||||||
@ -315,6 +325,12 @@ bool ClangTableGenMain(raw_ostream &OS, RecordKeeper &Records) {
|
|||||||
case GenClangAttrList:
|
case GenClangAttrList:
|
||||||
EmitClangAttrList(Records, OS);
|
EmitClangAttrList(Records, OS);
|
||||||
break;
|
break;
|
||||||
|
case GenClangAttrCanPrintLeftList:
|
||||||
|
EmitClangAttrPrintList("CanPrintOnLeft", Records, OS);
|
||||||
|
break;
|
||||||
|
case GenClangAttrMustPrintLeftList:
|
||||||
|
EmitClangAttrPrintList("PrintOnLeft", Records, OS);
|
||||||
|
break;
|
||||||
case GenClangAttrDocTable:
|
case GenClangAttrDocTable:
|
||||||
EmitClangAttrDocTable(Records, OS);
|
EmitClangAttrDocTable(Records, OS);
|
||||||
break;
|
break;
|
||||||
|
@ -39,6 +39,8 @@ void EmitClangAttrSubjectMatchRulesParserStringSwitches(
|
|||||||
void EmitClangAttrClass(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
|
void EmitClangAttrClass(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
|
||||||
void EmitClangAttrImpl(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
|
void EmitClangAttrImpl(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
|
||||||
void EmitClangAttrList(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
|
void EmitClangAttrList(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
|
||||||
|
void EmitClangAttrPrintList(const std::string &FieldName,
|
||||||
|
llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
|
||||||
void EmitClangAttrSubjectMatchRuleList(llvm::RecordKeeper &Records,
|
void EmitClangAttrSubjectMatchRuleList(llvm::RecordKeeper &Records,
|
||||||
llvm::raw_ostream &OS);
|
llvm::raw_ostream &OS);
|
||||||
void EmitClangAttrPCHRead(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
|
void EmitClangAttrPCHRead(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
|
||||||
|
Loading…
Reference in New Issue
Block a user