Comment parsing: actually check for a block command after "\param x"
This fixes PR15068.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@173539 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/AST/CommentParser.h b/include/clang/AST/CommentParser.h
index 5f6e0c5..8bf629b 100644
--- a/include/clang/AST/CommentParser.h
+++ b/include/clang/AST/CommentParser.h
@@ -86,6 +86,11 @@
Tok = Toks[0];
}
+ bool isTokBlockCommand() {
+ return Tok.is(tok::command) &&
+ Traits.getCommandInfo(Tok.getCommandID())->IsBlockCommand;
+ }
+
public:
Parser(Lexer &L, Sema &S, llvm::BumpPtrAllocator &Allocator,
const SourceManager &SourceMgr, DiagnosticsEngine &Diags,
diff --git a/lib/AST/CommentParser.cpp b/lib/AST/CommentParser.cpp
index a7ba013..5f45125 100644
--- a/lib/AST/CommentParser.cpp
+++ b/lib/AST/CommentParser.cpp
@@ -329,8 +329,7 @@
}
consumeToken();
- if (Tok.is(tok::command) &&
- Traits.getCommandInfo(Tok.getCommandID())->IsBlockCommand) {
+ if (isTokBlockCommand()) {
// Block command ahead. We can't nest block commands, so pretend that this
// command has an empty argument.
ParagraphComment *Paragraph = S.actOnParagraphComment(
@@ -362,10 +361,28 @@
Retokenizer.putBackLeftoverTokens();
}
- BlockContentComment *Block = parseParagraphOrBlockCommand();
- // Since we have checked for a block command, we should have parsed a
- // paragraph.
- ParagraphComment *Paragraph = cast<ParagraphComment>(Block);
+ // If there's a block command ahead, we will attach an empty paragraph to
+ // this command.
+ bool EmptyParagraph = false;
+ if (isTokBlockCommand())
+ EmptyParagraph = true;
+ else if (Tok.is(tok::newline)) {
+ Token PrevTok = Tok;
+ consumeToken();
+ EmptyParagraph = isTokBlockCommand();
+ putBack(PrevTok);
+ }
+
+ ParagraphComment *Paragraph;
+ if (EmptyParagraph)
+ Paragraph = S.actOnParagraphComment(ArrayRef<InlineContentComment *>());
+ else {
+ BlockContentComment *Block = parseParagraphOrBlockCommand();
+ // Since we have checked for a block command, we should have parsed a
+ // paragraph.
+ Paragraph = cast<ParagraphComment>(Block);
+ }
+
if (IsParam) {
S.actOnParamCommandFinish(PC, Paragraph);
return PC;
diff --git a/test/Analysis/temp-obj-dtors-cfg-output.cpp b/test/Analysis/temp-obj-dtors-cfg-output.cpp
index df9d906..c884475 100644
--- a/test/Analysis/temp-obj-dtors-cfg-output.cpp
+++ b/test/Analysis/temp-obj-dtors-cfg-output.cpp
@@ -1,6 +1,7 @@
// RUN: rm -f %t
// RUN: %clang_cc1 -analyze -analyzer-checker=debug.DumpCFG -analyzer-config cfg-temporary-dtors=true %s > %t 2>&1
// RUN: FileCheck --input-file=%t %s
+// XPASS: *
class A {
public:
diff --git a/test/Sema/warn-documentation.cpp b/test/Sema/warn-documentation.cpp
index 5678fd9..6a6b8dd 100644
--- a/test/Sema/warn-documentation.cpp
+++ b/test/Sema/warn-documentation.cpp
@@ -836,3 +836,31 @@
/// aaa \unknown aaa \unknown aaa
int test_nocrash9;
+
+// We used to crash on this. PR15068
+
+// expected-warning@+2 {{empty paragraph passed to '\param' command}}
+// expected-warning@+2 {{empty paragraph passed to '\param' command}}
+///@param x
+///@param y
+int test_nocrash10(int x, int y);
+
+// expected-warning@+2 {{empty paragraph passed to '\param' command}} expected-warning@+2 {{parameter 'x' not found in the function declaration}}
+// expected-warning@+2 {{empty paragraph passed to '\param' command}} expected-warning@+2 {{parameter 'y' not found in the function declaration}}
+///@param x
+///@param y
+int test_nocrash11();
+
+// expected-warning@+3 {{empty paragraph passed to '\param' command}} expected-warning@+3 {{parameter 'x' not found in the function declaration}}
+// expected-warning@+3 {{empty paragraph passed to '\param' command}} expected-warning@+3 {{parameter 'y' not found in the function declaration}}
+/**
+@param x
+@param y
+**/
+int test_nocrash12();
+
+// expected-warning@+2 {{empty paragraph passed to '\param' command}}
+// expected-warning@+1 {{empty paragraph passed to '\param' command}}
+///@param x@param y
+int test_nocrash13(int x, int y);
+