Skip to content

Commit 5e02d2a

Browse files
Implement #warning and #error (#14048)
* Implement #warning and #error * Fix #warning/#error in switch statements * Fix AST printing for #warning/#error * Add to test case * Add extra handling to ParseDeclPoundDiagnostic * fix dumping * Consume the right paren even in the failure case * Diagnose extra tokens on the same line after a diagnostic directive
1 parent ca7d186 commit 5e02d2a

34 files changed

+368
-15
lines changed

include/swift/AST/Attr.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,7 @@ class DeclAttribute : public AttributeBase {
295295

296296
// Cannot have any attributes.
297297
OnMissingMember = 0,
298+
OnPoundDiagnostic = 0,
298299

299300
// More coarse-grained aggregations for use in Attr.def.
300301
OnOperator = OnInfixOperator|OnPrefixOperator|OnPostfixOperator,

include/swift/AST/Decl.h

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "swift/AST/ClangNode.h"
2424
#include "swift/AST/ConcreteDeclRef.h"
2525
#include "swift/AST/DefaultArgumentKind.h"
26+
#include "swift/AST/DiagnosticConsumer.h"
2627
#include "swift/AST/GenericParamKey.h"
2728
#include "swift/AST/IfConfigClause.h"
2829
#include "swift/AST/LayoutConstraint.h"
@@ -107,6 +108,7 @@ enum class DescriptiveDeclKind : uint8_t {
107108
EnumCase,
108109
TopLevelCode,
109110
IfConfig,
111+
PoundDiagnostic,
110112
PatternBinding,
111113
Var,
112114
Param,
@@ -591,6 +593,14 @@ class alignas(1 << DeclAlignInBits) Decl {
591593
HadMissingEnd : 1
592594
);
593595

596+
SWIFT_INLINE_BITFIELD(PoundDiagnosticDecl, Decl, 1+1,
597+
/// `true` if the diagnostic is an error, `false` if it's a warning.
598+
IsError : 1,
599+
600+
/// Whether this diagnostic has already been emitted.
601+
HasBeenEmitted : 1
602+
);
603+
594604
SWIFT_INLINE_BITFIELD(MissingMemberDecl, Decl, 1+2,
595605
NumberOfFieldOffsetVectorEntries : 1,
596606
NumberOfVTableEntries : 2
@@ -2059,6 +2069,52 @@ class IfConfigDecl : public Decl {
20592069
}
20602070
};
20612071

2072+
class StringLiteralExpr;
2073+
2074+
class PoundDiagnosticDecl : public Decl {
2075+
SourceLoc StartLoc;
2076+
SourceLoc EndLoc;
2077+
StringLiteralExpr *Message;
2078+
2079+
public:
2080+
PoundDiagnosticDecl(DeclContext *Parent, bool IsError, SourceLoc StartLoc,
2081+
SourceLoc EndLoc, StringLiteralExpr *Message)
2082+
: Decl(DeclKind::PoundDiagnostic, Parent), StartLoc(StartLoc),
2083+
EndLoc(EndLoc), Message(Message) {
2084+
Bits.PoundDiagnosticDecl.IsError = IsError;
2085+
Bits.PoundDiagnosticDecl.HasBeenEmitted = false;
2086+
}
2087+
2088+
DiagnosticKind getKind() {
2089+
return isError() ? DiagnosticKind::Error : DiagnosticKind::Warning;
2090+
}
2091+
2092+
StringLiteralExpr *getMessage() { return Message; }
2093+
2094+
bool isError() {
2095+
return Bits.PoundDiagnosticDecl.IsError;
2096+
}
2097+
2098+
bool hasBeenEmitted() {
2099+
return Bits.PoundDiagnosticDecl.HasBeenEmitted;
2100+
}
2101+
2102+
void markEmitted() {
2103+
Bits.PoundDiagnosticDecl.HasBeenEmitted = true;
2104+
}
2105+
2106+
SourceLoc getEndLoc() const { return EndLoc; };
2107+
SourceLoc getLoc() const { return StartLoc; }
2108+
2109+
SourceRange getSourceRange() const {
2110+
return SourceRange(StartLoc, EndLoc);
2111+
}
2112+
2113+
static bool classof(const Decl *D) {
2114+
return D->getKind() == DeclKind::PoundDiagnostic;
2115+
}
2116+
};
2117+
20622118
/// ValueDecl - All named decls that are values in the language. These can
20632119
/// have a type, etc.
20642120
class ValueDecl : public Decl {

include/swift/AST/DeclNodes.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,7 @@ ITERABLE_GENERIC_DECL(Extension, Decl)
171171
CONTEXT_DECL(TopLevelCode, Decl)
172172
DECL(Import, Decl)
173173
DECL(IfConfig, Decl)
174+
DECL(PoundDiagnostic, Decl)
174175
DECL(PrecedenceGroup, Decl)
175176
DECL(MissingMember, Decl)
176177
DECL(PatternBinding, Decl)

include/swift/AST/DiagnosticsParse.def

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,17 @@ ERROR(extra_tokens_conditional_compilation_directive,none,
6868
ERROR(unexpected_rbrace_in_conditional_compilation_block,none,
6969
"unexpected '}' in conditional compilation block", ())
7070

71+
ERROR(pound_diagnostic_expected_string,none,
72+
"expected string literal in %select{#warning|#error}0 directive",(bool))
73+
ERROR(pound_diagnostic_expected,none,
74+
"expected '%0' in %select{#warning|#error}1 directive",(StringRef,bool))
75+
ERROR(pound_diagnostic_expected_parens,none,
76+
"%select{#warning|#error}0 directive requires parentheses",(bool))
77+
ERROR(pound_diagnostic_interpolation,none,
78+
"string interpolation is not allowed in %select{#warning|#error}0 directives",(bool))
79+
ERROR(extra_tokens_pound_diagnostic_directive,none,
80+
"extra tokens following %select{#warning|#error}0 directive", (bool))
81+
7182
ERROR(sourceLocation_expected,none,
7283
"expected '%0' in #sourceLocation directive", (StringRef))
7384

include/swift/AST/DiagnosticsSema.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1007,6 +1007,9 @@ ERROR(enum_element_not_materializable,none,
10071007
ERROR(missing_initializer_def,PointsToFirstBadToken,
10081008
"initializer requires a body", ())
10091009

1010+
WARNING(pound_warning, none, "%0", (StringRef))
1011+
ERROR(pound_error, none, "%0", (StringRef))
1012+
10101013
// Attributes
10111014

10121015
ERROR(operator_not_func,none,

include/swift/AST/Stmt.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -955,8 +955,8 @@ class SwitchStmt final : public LabeledStmt,
955955
}
956956

957957
private:
958-
struct AsCaseStmtWithSkippingIfConfig {
959-
AsCaseStmtWithSkippingIfConfig() {}
958+
struct AsCaseStmtWithSkippingNonCaseStmts {
959+
AsCaseStmtWithSkippingNonCaseStmts() {}
960960
Optional<CaseStmt*> operator()(const ASTNode &N) const {
961961
if (auto *CS = llvm::dyn_cast_or_null<CaseStmt>(N.dyn_cast<Stmt*>()))
962962
return CS;
@@ -966,11 +966,11 @@ class SwitchStmt final : public LabeledStmt,
966966

967967
public:
968968
using AsCaseStmtRange = OptionalTransformRange<ArrayRef<ASTNode>,
969-
AsCaseStmtWithSkippingIfConfig>;
969+
AsCaseStmtWithSkippingNonCaseStmts>;
970970

971971
/// Get the list of case clauses.
972972
AsCaseStmtRange getCases() const {
973-
return AsCaseStmtRange(getRawCases(), AsCaseStmtWithSkippingIfConfig());
973+
return AsCaseStmtRange(getRawCases(), AsCaseStmtWithSkippingNonCaseStmts());
974974
}
975975

976976
static bool classof(const Stmt *S) {

include/swift/AST/TypeMemberVisitor.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,11 @@ class TypeMemberVisitor : public DeclVisitor<ImplClass, RetTy> {
4848
return RetTy();
4949
}
5050

51+
// These decls are disregarded.
52+
RetTy visitPoundDiagnosticDecl(PoundDiagnosticDecl *D) {
53+
return RetTy();
54+
}
55+
5156
/// A convenience method to visit all the members.
5257
void visitMembers(NominalTypeDecl *D) {
5358
for (Decl *member : D->getMembers()) {

include/swift/Parse/Parser.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -755,6 +755,9 @@ class Parser {
755755
ParserResult<IfConfigDecl> parseIfConfig(
756756
llvm::function_ref<void(SmallVectorImpl<ASTNode> &, bool)> parseElements);
757757

758+
/// Parse a #error or #warning diagnostic.
759+
ParserResult<PoundDiagnosticDecl> parseDeclPoundDiagnostic();
760+
758761
/// Parse a #line/#sourceLocation directive.
759762
/// 'isLine = true' indicates parsing #line instead of #sourcelocation
760763
ParserStatus parseLineDirective(bool isLine = false);

include/swift/SIL/SILWitnessVisitor.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,10 @@ template <class T> class SILWitnessVisitor : public ASTVisitor<T> {
168168
// We only care about the active members, which were already subsumed by the
169169
// enclosing type.
170170
}
171+
172+
void visitPoundDiagnosticDecl(PoundDiagnosticDecl *pdd) {
173+
// We don't care about diagnostics at this stage.
174+
}
171175
};
172176

173177
} // end namespace swift

include/swift/Syntax/TokenKinds.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,8 @@ POUND_KEYWORD(keyPath)
259259
POUND_KEYWORD(line)
260260
POUND_KEYWORD(sourceLocation)
261261
POUND_KEYWORD(selector)
262+
POUND_KEYWORD(warning)
263+
POUND_KEYWORD(error)
262264

263265
// Keywords prefixed with a '#' that are build configurations.
264266
POUND_CONFIG(available)

lib/AST/ASTDumper.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1098,6 +1098,16 @@ namespace {
10981098
PrintWithColorRAII(OS, ParenthesisColor) << ')';
10991099
}
11001100

1101+
void visitPoundDiagnosticDecl(PoundDiagnosticDecl *PDD) {
1102+
printCommon(PDD, "pound_diagnostic_decl");
1103+
auto kind = PDD->isError() ? "error" : "warning";
1104+
OS << " kind=" << kind << "\n";
1105+
Indent += 2;
1106+
printRec(PDD->getMessage());
1107+
Indent -= 2;
1108+
PrintWithColorRAII(OS, ParenthesisColor) << ')';
1109+
}
1110+
11011111
void visitPrecedenceGroupDecl(PrecedenceGroupDecl *PGD) {
11021112
printCommon(PGD, "precedence_group_decl ");
11031113
OS << PGD->getName() << "\n";

lib/AST/ASTPrinter.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1917,6 +1917,17 @@ void PrintAST::visitIfConfigDecl(IfConfigDecl *ICD) {
19171917
Printer << tok::pound_endif;
19181918
}
19191919

1920+
void PrintAST::visitPoundDiagnosticDecl(PoundDiagnosticDecl *PDD) {
1921+
/// TODO: Should we even print #error/#warning?
1922+
if (PDD->isError()) {
1923+
Printer << tok::pound_error;
1924+
} else {
1925+
Printer << tok::pound_warning;
1926+
}
1927+
1928+
Printer << "(\"" << PDD->getMessage()->getValue() << "\")";
1929+
}
1930+
19201931
void PrintAST::visitTypeAliasDecl(TypeAliasDecl *decl) {
19211932
printDocumentationComment(decl);
19221933
printAttributes(decl);

lib/AST/ASTScope.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -881,6 +881,7 @@ ASTScope *ASTScope::createIfNeeded(const ASTScope *parent, Decl *decl) {
881881
case DeclKind::Param:
882882
case DeclKind::EnumElement:
883883
case DeclKind::IfConfig:
884+
case DeclKind::PoundDiagnostic:
884885
case DeclKind::MissingMember:
885886
// These declarations do not introduce scopes.
886887
return nullptr;

lib/AST/ASTWalker.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,11 @@ class Traversal : public ASTVisitor<Traversal, Expr*, Stmt*,
188188
return false;
189189
}
190190

191+
bool visitPoundDiagnosticDecl(PoundDiagnosticDecl *PDD) {
192+
// By default, ignore #error/#warning.
193+
return false;
194+
}
195+
191196
bool visitOperatorDecl(OperatorDecl *OD) {
192197
return false;
193198
}
@@ -1476,7 +1481,8 @@ Stmt *Traversal::visitSwitchStmt(SwitchStmt *S) {
14761481
} else
14771482
return nullptr;
14781483
} else {
1479-
assert(isa<IfConfigDecl>(N.get<Decl*>()));
1484+
assert(isa<IfConfigDecl>(N.get<Decl*>()) ||
1485+
isa<PoundDiagnosticDecl>(N.get<Decl*>()));
14801486
if (doIt(N.get<Decl*>()))
14811487
return nullptr;
14821488
}

lib/AST/Decl.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ DescriptiveDeclKind Decl::getDescriptiveKind() const {
125125
TRIVIAL_KIND(EnumCase);
126126
TRIVIAL_KIND(TopLevelCode);
127127
TRIVIAL_KIND(IfConfig);
128+
TRIVIAL_KIND(PoundDiagnostic);
128129
TRIVIAL_KIND(PatternBinding);
129130
TRIVIAL_KIND(PrecedenceGroup);
130131
TRIVIAL_KIND(InfixOperator);
@@ -235,6 +236,7 @@ StringRef Decl::getDescriptiveKindName(DescriptiveDeclKind K) {
235236
ENTRY(EnumCase, "case");
236237
ENTRY(TopLevelCode, "top-level code");
237238
ENTRY(IfConfig, "conditional block");
239+
ENTRY(PoundDiagnostic, "diagnostic");
238240
ENTRY(PatternBinding, "pattern binding");
239241
ENTRY(Var, "var");
240242
ENTRY(Param, "parameter");
@@ -769,6 +771,7 @@ ImportKind ImportDecl::getBestImportKind(const ValueDecl *VD) {
769771
case DeclKind::PostfixOperator:
770772
case DeclKind::EnumCase:
771773
case DeclKind::IfConfig:
774+
case DeclKind::PoundDiagnostic:
772775
case DeclKind::PrecedenceGroup:
773776
case DeclKind::MissingMember:
774777
llvm_unreachable("not a ValueDecl");
@@ -1535,6 +1538,7 @@ bool ValueDecl::isDefinition() const {
15351538
case DeclKind::PrefixOperator:
15361539
case DeclKind::PostfixOperator:
15371540
case DeclKind::IfConfig:
1541+
case DeclKind::PoundDiagnostic:
15381542
case DeclKind::PrecedenceGroup:
15391543
case DeclKind::MissingMember:
15401544
assert(!isa<ValueDecl>(this));
@@ -1578,6 +1582,7 @@ bool ValueDecl::isInstanceMember() const {
15781582
case DeclKind::PrefixOperator:
15791583
case DeclKind::PostfixOperator:
15801584
case DeclKind::IfConfig:
1585+
case DeclKind::PoundDiagnostic:
15811586
case DeclKind::PrecedenceGroup:
15821587
case DeclKind::MissingMember:
15831588
llvm_unreachable("Not a ValueDecl");

lib/AST/Stmt.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -404,7 +404,8 @@ SwitchStmt *SwitchStmt::create(LabeledStmtInfo LabelInfo, SourceLoc SwitchLoc,
404404
#ifndef NDEBUG
405405
for (auto N : Cases)
406406
assert((N.is<Stmt*>() && isa<CaseStmt>(N.get<Stmt*>())) ||
407-
(N.is<Decl*>() && isa<IfConfigDecl>(N.get<Decl*>())));
407+
(N.is<Decl*>() && (isa<IfConfigDecl>(N.get<Decl*>()) ||
408+
isa<PoundDiagnosticDecl>(N.get<Decl*>()))));
408409
#endif
409410

410411
void *p = C.Allocate(totalSizeToAlloc<ASTNode>(Cases.size()),

lib/FrontendTool/ReferenceDependencies.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ static bool declIsPrivate(const Decl *member) {
6969
case DeclKind::EnumCase:
7070
case DeclKind::TopLevelCode:
7171
case DeclKind::IfConfig:
72+
case DeclKind::PoundDiagnostic:
7273
return true;
7374

7475
case DeclKind::Extension:
@@ -240,6 +241,7 @@ bool swift::emitReferenceDependencies(DiagnosticEngine &diags,
240241
case DeclKind::PatternBinding:
241242
case DeclKind::TopLevelCode:
242243
case DeclKind::IfConfig:
244+
case DeclKind::PoundDiagnostic:
243245
// No action necessary.
244246
break;
245247

lib/IDE/CodeCompletion.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -548,6 +548,7 @@ CodeCompletionResult::getCodeCompletionDeclKind(const Decl *D) {
548548
case DeclKind::EnumCase:
549549
case DeclKind::TopLevelCode:
550550
case DeclKind::IfConfig:
551+
case DeclKind::PoundDiagnostic:
551552
case DeclKind::MissingMember:
552553
llvm_unreachable("not expecting such a declaration result");
553554
case DeclKind::Module:

lib/IRGen/GenDecl.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1881,7 +1881,8 @@ void IRGenModule::emitGlobalDecl(Decl *D) {
18811881
case DeclKind::TypeAlias:
18821882
case DeclKind::GenericTypeParam:
18831883
case DeclKind::AssociatedType:
1884-
case DeclKind::IfConfig:
1884+
case DeclKind::IfConfig:
1885+
case DeclKind::PoundDiagnostic:
18851886
return;
18861887

18871888
case DeclKind::Enum:
@@ -3345,6 +3346,7 @@ void IRGenModule::emitNestedTypeDecls(DeclRange members) {
33453346
llvm_unreachable("decl not allowed in type context");
33463347

33473348
case DeclKind::IfConfig:
3349+
case DeclKind::PoundDiagnostic:
33483350
continue;
33493351

33503352
case DeclKind::PatternBinding:

lib/Index/IndexSymbol.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,7 @@ SymbolInfo index::getSymbolInfoForDecl(const Decl *D) {
214214
case DeclKind::EnumCase:
215215
case DeclKind::TopLevelCode:
216216
case DeclKind::IfConfig:
217+
case DeclKind::PoundDiagnostic:
217218
case DeclKind::MissingMember:
218219
case DeclKind::Module:
219220
break;

0 commit comments

Comments
 (0)