diff --git a/clang/include/clang/Basic/DiagnosticLexKinds.td b/clang/include/clang/Basic/DiagnosticLexKinds.td index ed6ff20f5c42..2fc9664f49e5 100644 --- a/clang/include/clang/Basic/DiagnosticLexKinds.td +++ b/clang/include/clang/Basic/DiagnosticLexKinds.td @@ -490,6 +490,8 @@ def warn_pragma_diagnostic_unknown_warning : // - #pragma __debug def warn_pragma_debug_unexpected_command : Warning< "unexpected debug command '%0'">, InGroup; +def warn_pragma_debug_missing_argument : Warning< + "missing argument to debug command '%0'">, InGroup; def err_defined_macro_name : Error<"'defined' cannot be used as a macro name">; def err_paste_at_start : Error< diff --git a/clang/include/clang/Basic/TokenKinds.def b/clang/include/clang/Basic/TokenKinds.def index 65a77accf92a..026945141d24 100644 --- a/clang/include/clang/Basic/TokenKinds.def +++ b/clang/include/clang/Basic/TokenKinds.def @@ -699,6 +699,11 @@ ANNOTATION(pragma_parser_crash) // handles them. ANNOTATION(pragma_captured) +// Annotation for #pragma clang __debug dump... +// The lexer produces these so that the parser and semantic analysis can +// look up and dump the operand. +ANNOTATION(pragma_dump) + // Annotation for #pragma ms_struct... // The lexer produces these so that they only take effect when the parser // handles them. diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 82b779879c20..8017f19c6184 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -501,6 +501,10 @@ private: /// #pragma align... void HandlePragmaAlign(); + /// \brief Handle the annotation token produced for + /// #pragma clang __debug dump... + void HandlePragmaDump(); + /// \brief Handle the annotation token produced for /// #pragma weak id... void HandlePragmaWeak(); diff --git a/clang/include/clang/Sema/Lookup.h b/clang/include/clang/Sema/Lookup.h index 87c40f0cf206..7efb19f57419 100644 --- a/clang/include/clang/Sema/Lookup.h +++ b/clang/include/clang/Sema/Lookup.h @@ -515,6 +515,7 @@ public: configure(); } + void dump(); void print(raw_ostream &); /// Suppress the diagnostics that would normally fire because of this diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index c82684ee4583..0d49298bfc40 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -7629,6 +7629,9 @@ public: void ActOnPragmaMSInitSeg(SourceLocation PragmaLocation, StringLiteral *SegmentName); + /// \brief Called on #pragma clang __debug dump II + void ActOnPragmaDump(Scope *S, SourceLocation Loc, IdentifierInfo *II); + /// ActOnPragmaDetectMismatch - Call on well-formed \#pragma detect_mismatch void ActOnPragmaDetectMismatch(StringRef Name, StringRef Value); diff --git a/clang/lib/AST/ASTDumper.cpp b/clang/lib/AST/ASTDumper.cpp index e7fee0316b69..4622a75ac2c6 100644 --- a/clang/lib/AST/ASTDumper.cpp +++ b/clang/lib/AST/ASTDumper.cpp @@ -1055,6 +1055,7 @@ void ASTDumper::VisitTypedefDecl(const TypedefDecl *D) { dumpType(D->getUnderlyingType()); if (D->isModulePrivate()) OS << " __module_private__"; + dumpTypeAsChild(D->getUnderlyingType()); } void ASTDumper::VisitEnumDecl(const EnumDecl *D) { @@ -1226,6 +1227,7 @@ void ASTDumper::VisitNamespaceAliasDecl(const NamespaceAliasDecl *D) { void ASTDumper::VisitTypeAliasDecl(const TypeAliasDecl *D) { dumpName(D); dumpType(D->getUnderlyingType()); + dumpTypeAsChild(D->getUnderlyingType()); } void ASTDumper::VisitTypeAliasTemplateDecl(const TypeAliasTemplateDecl *D) { @@ -1419,6 +1421,8 @@ void ASTDumper::VisitUnresolvedUsingValueDecl(const UnresolvedUsingValueDecl *D) void ASTDumper::VisitUsingShadowDecl(const UsingShadowDecl *D) { OS << ' '; dumpBareDeclRef(D->getTargetDecl()); + if (auto *TD = dyn_cast(D->getUnderlyingDecl())) + dumpTypeAsChild(TD->getTypeForDecl()); } void ASTDumper::VisitLinkageSpecDecl(const LinkageSpecDecl *D) { diff --git a/clang/lib/Lex/Pragma.cpp b/clang/lib/Lex/Pragma.cpp index 3134790ccb90..afb41a240776 100644 --- a/clang/lib/Lex/Pragma.cpp +++ b/clang/lib/Lex/Pragma.cpp @@ -876,6 +876,22 @@ struct PragmaDebugHandler : public PragmaHandler { Crasher.setKind(tok::annot_pragma_parser_crash); Crasher.setAnnotationRange(SourceRange(Tok.getLocation())); PP.EnterToken(Crasher); + } else if (II->isStr("dump")) { + Token Identifier; + PP.LexUnexpandedToken(Identifier); + if (auto *DumpII = Identifier.getIdentifierInfo()) { + Token DumpAnnot; + DumpAnnot.startToken(); + DumpAnnot.setKind(tok::annot_pragma_dump); + DumpAnnot.setAnnotationRange( + SourceRange(Tok.getLocation(), Identifier.getLocation())); + DumpAnnot.setAnnotationValue(DumpII); + PP.DiscardUntilEndOfDirective(); + PP.EnterToken(DumpAnnot); + } else { + PP.Diag(Identifier, diag::warn_pragma_debug_missing_argument) + << II->getName(); + } } else if (II->isStr("llvm_fatal_error")) { llvm::report_fatal_error("#pragma clang __debug llvm_fatal_error"); } else if (II->isStr("llvm_unreachable")) { @@ -887,7 +903,8 @@ struct PragmaDebugHandler : public PragmaHandler { if (MacroII) PP.dumpMacroInfo(MacroII); else - PP.Diag(MacroName, diag::warn_pragma_diagnostic_invalid); + PP.Diag(MacroName, diag::warn_pragma_debug_missing_argument) + << II->getName(); } else if (II->isStr("overflow_stack")) { DebugOverflowStack(); } else if (II->isStr("handle_crash")) { diff --git a/clang/lib/Parse/ParsePragma.cpp b/clang/lib/Parse/ParsePragma.cpp index 4430eb8d03da..bc70942851e2 100644 --- a/clang/lib/Parse/ParsePragma.cpp +++ b/clang/lib/Parse/ParsePragma.cpp @@ -377,6 +377,14 @@ void Parser::HandlePragmaAlign() { Actions.ActOnPragmaOptionsAlign(Kind, PragmaLoc); } +void Parser::HandlePragmaDump() { + assert(Tok.is(tok::annot_pragma_dump)); + IdentifierInfo *II = + reinterpret_cast(Tok.getAnnotationValue()); + Actions.ActOnPragmaDump(getCurScope(), Tok.getLocation(), II); + ConsumeToken(); +} + void Parser::HandlePragmaWeak() { assert(Tok.is(tok::annot_pragma_weak)); SourceLocation PragmaLoc = ConsumeToken(); diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp index 717bcff0c168..1dafae0c94c9 100644 --- a/clang/lib/Parse/ParseStmt.cpp +++ b/clang/lib/Parse/ParseStmt.cpp @@ -366,6 +366,10 @@ Retry: case tok::annot_pragma_loop_hint: ProhibitAttributes(Attrs); return ParsePragmaLoopHint(Stmts, OnlyStatement, TrailingElseLoc, Attrs); + + case tok::annot_pragma_dump: + HandlePragmaDump(); + return StmtEmpty(); } // If we reached this code, the statement must end in a semicolon. @@ -893,6 +897,9 @@ void Parser::ParseCompoundStatementLeadingPragmas() { case tok::annot_pragma_ms_vtordisp: HandlePragmaMSVtorDisp(); break; + case tok::annot_pragma_dump: + HandlePragmaDump(); + break; default: checkForPragmas = false; break; diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index b3eeb9d58ff4..ccefb3dd3f5d 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -668,6 +668,9 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs, case tok::annot_pragma_ms_pragma: HandlePragmaMSPragma(); return DeclGroupPtrTy(); + case tok::annot_pragma_dump: + HandlePragmaDump(); + return DeclGroupPtrTy(); case tok::semi: // Either a C++11 empty-declaration or attribute-declaration. SingleDecl = Actions.ActOnEmptyDeclaration(getCurScope(), diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp index 1d7b15c35d12..45dc2e33da93 100644 --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/lib/Sema/SemaLookup.cpp @@ -650,6 +650,13 @@ void LookupResult::print(raw_ostream &Out) { } } +LLVM_DUMP_METHOD void LookupResult::dump() { + llvm::errs() << "lookup results for " << getLookupName().getAsString() + << ":\n"; + for (NamedDecl *D : *this) + D->dump(); +} + /// \brief Lookup a builtin function, when name lookup would otherwise /// fail. static bool LookupBuiltin(Sema &S, LookupResult &R) { @@ -4991,3 +4998,12 @@ const Sema::TypoExprState &Sema::getTypoExprState(TypoExpr *TE) const { void Sema::clearDelayedTypo(TypoExpr *TE) { DelayedTypos.erase(TE); } + +void Sema::ActOnPragmaDump(Scope *S, SourceLocation IILoc, IdentifierInfo *II) { + DeclarationNameInfo Name(II, IILoc); + LookupResult R(*this, Name, LookupAnyName, Sema::NotForRedeclaration); + R.suppressDiagnostics(); + R.setHideTags(false); + LookupName(R, S); + R.dump(); +} diff --git a/clang/test/Misc/ast-dump-lookups.cpp b/clang/test/Misc/ast-dump-lookups.cpp index 5c6da48b3afb..2d235010cb73 100644 --- a/clang/test/Misc/ast-dump-lookups.cpp +++ b/clang/test/Misc/ast-dump-lookups.cpp @@ -1,16 +1,31 @@ // RUN: %clang_cc1 -std=c++11 -ast-dump -ast-dump-filter Test %s | FileCheck -check-prefix DECLS %s // RUN: %clang_cc1 -std=c++11 -ast-dump-lookups -ast-dump-filter Test %s | FileCheck -check-prefix LOOKUPS %s // RUN: %clang_cc1 -std=c++11 -ast-dump -ast-dump-lookups -ast-dump-filter Test %s | FileCheck -check-prefix DECLS-LOOKUPS %s +// RUN: %clang_cc1 -std=c++11 -DPRAGMA -fsyntax-only %s 2>&1 | FileCheck -check-prefix PRAGMA %s namespace Test { + typedef int T; extern int a; int a = 0; } +#ifdef PRAGMA +#pragma clang __debug dump Test +// PRAGMA: lookup results for Test: +// PRAGMA-NEXT: NamespaceDecl {{.*}} Test +// PRAGMA-NEXT: |-TypedefDecl {{.*}} T 'int' +// PRAGMA-NEXT: | `-BuiltinType {{.*}} 'int' +// PRAGMA-NEXT: |-VarDecl [[EXTERN_A:0x[^ ]*]] {{.*}} a 'int' extern +// PRAGMA-NEXT: `-VarDecl {{.*}} prev [[EXTERN_A]] {{.*}} a 'int' cinit +// PRAGMA-NEXT: `-IntegerLiteral {{.*}} 'int' 0 +#endif + namespace Test { } // DECLS: Dumping Test: // DECLS-NEXT: NamespaceDecl {{.*}} Test +// DECLS-NEXT: |-TypedefDecl {{.*}} T 'int' +// DECLS-NEXT: | `-BuiltinType {{.*}} 'int' // DECLS-NEXT: |-VarDecl [[EXTERN_A:0x[^ ]*]] {{.*}} a 'int' extern // DECLS-NEXT: `-VarDecl {{.*}} prev [[EXTERN_A]] {{.*}} a 'int' cinit // DECLS-NEXT: `-IntegerLiteral {{.*}} 'int' 0 @@ -20,15 +35,15 @@ namespace Test { } // LOOKUPS: Dumping Test: // LOOKUPS-NEXT: StoredDeclsMap Namespace {{.*}} 'Test' -// LOOKUPS-NEXT: `-DeclarationName 'a' -// LOOKUPS-NEXT: `-Var {{.*}} 'a' 'int' +// LOOKUPS: DeclarationName 'a' +// LOOKUPS-NEXT: `-Var {{.*}} 'a' 'int' // // LOOKUPS: Dumping Test: // LOOKUPS-NEXT: Lookup map is in primary DeclContext // DECLS-LOOKUPS: Dumping Test: // DECLS-LOOKUPS-NEXT: StoredDeclsMap Namespace {{.*}} 'Test' -// DECLS-LOOKUPS-NEXT: `-DeclarationName 'a' +// DECLS-LOOKUPS: -DeclarationName 'a' // DECLS-LOOKUPS-NEXT: `-Var [[A:[^ ]*]] 'a' 'int' // DECLS-LOOKUPS-NEXT: |-VarDecl [[EXTERN_A:0x[^ ]*]] {{.*}} a 'int' extern // DECLS-LOOKUPS-NEXT: `-VarDecl [[A]] prev [[EXTERN_A]] {{.*}} a 'int' cinit