Patch updated. Summary of change:
- Introduce a new table-gen generated function isCXX11Syntax to Attr.
- Always print out C++11 attributes of a function declaration after function
declarator-id to make sure they appertain to function itself.
Hi rsmith,
http://llvm-reviews.chandlerc.com/D395
CHANGE SINCE LAST DIFF
http://llvm-reviews.chandlerc.com/D395?vs=1120&id=1159#toc
Files:
include/clang/AST/Attr.h
utils/TableGen/ClangAttrEmitter.cpp
lib/AST/DeclPrinter.cpp
test/SemaCXX/cxx11-attr-print.cpp
Index: include/clang/AST/Attr.h
===================================================================
--- include/clang/AST/Attr.h
+++ include/clang/AST/Attr.h
@@ -102,6 +102,9 @@
// Pretty print this attribute.
virtual void printPretty(raw_ostream &OS,
const PrintingPolicy &Policy) const = 0;
+
+ /// \brief Return true if the attribute is using C++11 syntax.
+ virtual bool isCXX11Syntax() const = 0;
};
class InheritableAttr : public Attr {
Index: utils/TableGen/ClangAttrEmitter.cpp
===================================================================
--- utils/TableGen/ClangAttrEmitter.cpp
+++ utils/TableGen/ClangAttrEmitter.cpp
@@ -829,6 +829,48 @@
OS << "}\n\n";
}
+/// \brief Emit function implementation that tells if the attribute
+/// is using C++11 syntax.
+static void writeIsCXX11SyntaxFunction(Record &R,
+ std::vector<Argument*> &Args,
+ raw_ostream &OS) {
+ std::vector<Record*> Spellings = R.getValueAsListOfDefs("Spellings");
+
+ OS << "bool " << R.getName() << "Attr::isCXX11Syntax() const {\n";
+
+ // Each attribute defined in Attr.td that has a C++11 syntax also
+ // has a spelling.
+ if (Spellings.size() == 0) {
+ OS << " return false;\n}\n\n";
+ return;
+ }
+
+ OS << " switch (SpellingListIndex) {\n";
+
+ for (unsigned I = 0; I < Spellings.size(); ++ I) {
+ std::string Name = Spellings[I]->getValueAsString("Name");
+ std::string Variety = Spellings[I]->getValueAsString("Variety");
+
+ bool Result;
+ if (Variety == "CXX11") {
+ Result = true;
+ } else if (Variety == "Keyword" && (Name == "alignas" ||
+ Name == "_Alignas")) {
+ Result = true;
+ } else {
+ Result = false;
+ }
+
+ OS << " case " << I << " : return " << Result << ";\n";
+ }
+
+ // End of the switch statement.
+ OS << " }\n";
+ OS << " llvm_unreachable(\"Unknown attribute spelling!\");\n";
+ // End of the function.
+ OS << "}\n\n";
+}
+
/// \brief Return the index of a spelling in a spelling list.
static unsigned getSpellingListIndex(const std::vector<Record*> &SpellingList,
const Record &Spelling) {
@@ -948,6 +990,8 @@
OS << " virtual void printPretty(raw_ostream &OS,\n"
<< " const PrintingPolicy &Policy) const;\n";
+ OS << " virtual bool isCXX11Syntax() const;\n";
+
writeAttrAccessorDefinition(R, OS);
for (ai = Args.begin(); ai != ae; ++ai) {
@@ -1003,6 +1047,7 @@
OS << ", getSpellingListIndex());\n}\n\n";
writePrettyPrintFunction(R, Args, OS);
+ writeIsCXX11SyntaxFunction(R, Args, OS);
}
}
Index: lib/AST/DeclPrinter.cpp
===================================================================
--- lib/AST/DeclPrinter.cpp
+++ lib/AST/DeclPrinter.cpp
@@ -86,6 +86,8 @@
void PrintTemplateParameters(const TemplateParameterList *Params,
const TemplateArgumentList *Args = 0);
void prettyPrintAttributes(Decl *D);
+ /// \brief Pretty print a list of attributes to an output stream.
+ void prettyPrintAttributes(AttrVec &Attrs, llvm::raw_ostream &OS);
};
}
@@ -186,7 +188,7 @@
void DeclPrinter::prettyPrintAttributes(Decl *D) {
if (Policy.PolishForDeclaration)
return;
-
+
if (D->hasAttrs()) {
AttrVec &Attrs = D->getAttrs();
for (AttrVec::const_iterator i=Attrs.begin(), e=Attrs.end(); i!=e; ++i) {
@@ -196,6 +198,16 @@
}
}
+void DeclPrinter::prettyPrintAttributes(AttrVec &Attrs, llvm::raw_ostream &OS) {
+ if (Policy.PolishForDeclaration)
+ return;
+
+ for (AttrVec::const_iterator I = Attrs.begin(),
+ E = Attrs.end(); I != E; ++I) {
+ (*I)->printPretty(OS, Policy);
+ }
+}
+
void DeclPrinter::ProcessDeclGroup(SmallVectorImpl<Decl*>& Decls) {
this->Indent();
Decl::printGroup(Decls.data(), Decls.size(), Out, Policy, Indentation);
@@ -388,6 +400,21 @@
}
void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
+ // Classify attributes of D into two groups: C++11 attributes
+ // and none C++11 attributes so we can print them seperately.
+ AttrVec CXX11Attrs, OtherAttrs;
+ if (D->hasAttrs()) {
+ AttrVec Attrs = D->getAttrs();
+ for (AttrVec::const_iterator I = Attrs.begin(),
+ E = Attrs.end(); I != E; ++I) {
+ Attr *Attribute = *I;
+ if (Attribute->isCXX11Syntax())
+ CXX11Attrs.push_back(Attribute);
+ else
+ OtherAttrs.push_back(Attribute);
+ }
+ }
+
CXXConstructorDecl *CDecl = dyn_cast<CXXConstructorDecl>(D);
if (!Policy.SuppressSpecifiers) {
switch (D->getStorageClassAsWritten()) {
@@ -417,6 +444,16 @@
}
if (isa<FunctionType>(Ty)) {
+ // Print C++11 attributes between function declarator-id and
+ // parameter-type-list so these attributes appertain to function
+ // itself.
+ std::string AttrStr;
+ llvm::raw_string_ostream OS(AttrStr);
+ prettyPrintAttributes(CXX11Attrs, OS);
+ Proto += OS.str();
+ if (CXX11Attrs.size())
+ Proto += " ";
+
const FunctionType *AFT = Ty->getAs<FunctionType>();
const FunctionProtoType *FT = 0;
if (D->hasWrittenPrototype())
@@ -554,7 +591,7 @@
Ty.print(Out, Policy, Proto);
}
- prettyPrintAttributes(D);
+ prettyPrintAttributes(OtherAttrs, Out);
if (D->isPure())
Out << " = 0";
Index: test/SemaCXX/cxx11-attr-print.cpp
===================================================================
--- test/SemaCXX/cxx11-attr-print.cpp
+++ test/SemaCXX/cxx11-attr-print.cpp
@@ -31,24 +31,22 @@
// CHECK: int f1() __attribute__((warn_unused_result));
int f1() __attribute__((warn_unused_result));
-// CHECK: {{\[}}[clang::warn_unused_result]];
+// CHECK: int f2 {{\[}}[clang::warn_unused_result]] ();
int f2 [[clang::warn_unused_result]] ();
-// CHECK: {{\[}}[gnu::warn_unused_result]];
+// CHECK: int f3 {{\[}}[gnu::warn_unused_result]] ();
int f3 [[gnu::warn_unused_result]] ();
-// FIXME: ast-print need to print C++11
-// attribute after function declare-id.
-// CHECK: {{\[}}[noreturn]];
+// CHECK: void f4 {{\[}}[noreturn]] ();
void f4 [[noreturn]] ();
-// CHECK: {{\[}}[std::noreturn]];
+// CHECK: void f5 {{\[}}[std::noreturn]] ();
void f5 [[std::noreturn]] ();
// CHECK: __attribute__((gnu_inline));
inline void f6() __attribute__((gnu_inline));
-// CHECK: {{\[}}[gnu::gnu_inline]];
+// CHECK: inline void f7 {{\[}}[gnu::gnu_inline]] ();
inline void f7 [[gnu::gnu_inline]] ();
// arguments printing
@@ -58,7 +56,7 @@
// CHECK: int m __attribute__((aligned(4
// CHECK: int n alignas(4
// CHECK: static int f() __attribute__((pure))
-// CHECK: static int g() {{\[}}[gnu::pure]]
+// CHECK: static int g {{\[}}[gnu::pure]] ()
template <typename T> struct S {
__attribute__((aligned(4))) int m;
alignas(4) int n;
@@ -73,5 +71,8 @@
// CHECK: int m __attribute__((aligned(4
// CHECK: int n alignas(4
// CHECK: static int f() __attribute__((pure))
-// CHECK: static int g() {{\[}}[gnu::pure]]
+// CHECK: static int g {{\[}}[gnu::pure]] ()
template struct S<int>;
+
+// CHECK: void combo {{\[}}[gnu::deprecated("")]] {{\[}}[gnu::pure]] () __attribute__((always_inline));
+void combo [[gnu::pure]] [[gnu::deprecated("")]] () __attribute__((always_inline));
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits