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)

0 commit comments

Comments
 (0)