New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement #warning and #error #14048

Merged
merged 8 commits into from Feb 3, 2018
Copy path View file
@@ -295,6 +295,7 @@ class DeclAttribute : public AttributeBase {
// Cannot have any attributes.
OnMissingMember = 0,
OnPoundDiagnostic = 0,
// More coarse-grained aggregations for use in Attr.def.
OnOperator = OnInfixOperator|OnPrefixOperator|OnPostfixOperator,
Copy path View file
@@ -23,6 +23,7 @@
#include "swift/AST/ClangNode.h"
#include "swift/AST/ConcreteDeclRef.h"
#include "swift/AST/DefaultArgumentKind.h"
#include "swift/AST/DiagnosticConsumer.h"
#include "swift/AST/GenericParamKey.h"
#include "swift/AST/IfConfigClause.h"
#include "swift/AST/LayoutConstraint.h"
@@ -107,6 +108,7 @@ enum class DescriptiveDeclKind : uint8_t {
EnumCase,
TopLevelCode,
IfConfig,
PoundDiagnostic,
PatternBinding,
Var,
Param,
@@ -591,6 +593,14 @@ class alignas(1 << DeclAlignInBits) Decl {
HadMissingEnd : 1
);
SWIFT_INLINE_BITFIELD(PoundDiagnosticDecl, Decl, 1+1,
/// `true` if the diagnostic is an error, `false` if it's a warning.
IsError : 1,
/// Whether this diagnostic has already been emitted.
HasBeenEmitted : 1
);
SWIFT_INLINE_BITFIELD(MissingMemberDecl, Decl, 1+2,
NumberOfFieldOffsetVectorEntries : 1,
NumberOfVTableEntries : 2
@@ -2059,6 +2069,52 @@ class IfConfigDecl : public Decl {
}
};
class StringLiteralExpr;
class PoundDiagnosticDecl : public Decl {
SourceLoc StartLoc;
SourceLoc EndLoc;
StringLiteralExpr *Message;
public:
PoundDiagnosticDecl(DeclContext *Parent, bool IsError, SourceLoc StartLoc,
SourceLoc EndLoc, StringLiteralExpr *Message)
: Decl(DeclKind::PoundDiagnostic, Parent), StartLoc(StartLoc),
EndLoc(EndLoc), Message(Message) {
Bits.PoundDiagnosticDecl.IsError = IsError;
Bits.PoundDiagnosticDecl.HasBeenEmitted = false;
}
DiagnosticKind getKind() {
return isError() ? DiagnosticKind::Error : DiagnosticKind::Warning;
}
StringLiteralExpr *getMessage() { return Message; }
bool isError() {
return Bits.PoundDiagnosticDecl.IsError;
}
bool hasBeenEmitted() {
return Bits.PoundDiagnosticDecl.HasBeenEmitted;
}
void markEmitted() {
Bits.PoundDiagnosticDecl.HasBeenEmitted = true;
}
SourceLoc getEndLoc() const { return EndLoc; };
SourceLoc getLoc() const { return StartLoc; }
SourceRange getSourceRange() const {
return SourceRange(StartLoc, EndLoc);
}
static bool classof(const Decl *D) {
return D->getKind() == DeclKind::PoundDiagnostic;
}
};
/// ValueDecl - All named decls that are values in the language. These can
/// have a type, etc.
class ValueDecl : public Decl {
@@ -171,6 +171,7 @@ ITERABLE_GENERIC_DECL(Extension, Decl)
CONTEXT_DECL(TopLevelCode, Decl)
DECL(Import, Decl)
DECL(IfConfig, Decl)
DECL(PoundDiagnostic, Decl)
DECL(PrecedenceGroup, Decl)
DECL(MissingMember, Decl)
DECL(PatternBinding, Decl)
@@ -68,6 +68,17 @@ ERROR(extra_tokens_conditional_compilation_directive,none,
ERROR(unexpected_rbrace_in_conditional_compilation_block,none,
"unexpected '}' in conditional compilation block", ())
ERROR(pound_diagnostic_expected_string,none,
"expected string literal in %select{#warning|#error}0 directive",(bool))
ERROR(pound_diagnostic_expected,none,
"expected '%0' in %select{#warning|#error}1 directive",(StringRef,bool))
ERROR(pound_diagnostic_expected_parens,none,
"%select{#warning|#error}0 directive requires parentheses",(bool))
ERROR(pound_diagnostic_interpolation,none,
"string interpolation is not allowed in %select{#warning|#error}0 directives",(bool))
ERROR(extra_tokens_pound_diagnostic_directive,none,
"extra tokens following %select{#warning|#error}0 directive", (bool))
ERROR(sourceLocation_expected,none,
"expected '%0' in #sourceLocation directive", (StringRef))
@@ -1007,6 +1007,9 @@ ERROR(enum_element_not_materializable,none,
ERROR(missing_initializer_def,PointsToFirstBadToken,
"initializer requires a body", ())
WARNING(pound_warning, none, "%0", (StringRef))
ERROR(pound_error, none, "%0", (StringRef))
// Attributes
ERROR(operator_not_func,none,
Copy path View file
@@ -955,8 +955,8 @@ class SwitchStmt final : public LabeledStmt,
}
private:
struct AsCaseStmtWithSkippingIfConfig {
AsCaseStmtWithSkippingIfConfig() {}
struct AsCaseStmtWithSkippingNonCaseStmts {
AsCaseStmtWithSkippingNonCaseStmts() {}
Optional<CaseStmt*> operator()(const ASTNode &N) const {
if (auto *CS = llvm::dyn_cast_or_null<CaseStmt>(N.dyn_cast<Stmt*>()))
return CS;
@@ -966,11 +966,11 @@ class SwitchStmt final : public LabeledStmt,
public:
using AsCaseStmtRange = OptionalTransformRange<ArrayRef<ASTNode>,
AsCaseStmtWithSkippingIfConfig>;
AsCaseStmtWithSkippingNonCaseStmts>;
/// Get the list of case clauses.
AsCaseStmtRange getCases() const {
return AsCaseStmtRange(getRawCases(), AsCaseStmtWithSkippingIfConfig());
return AsCaseStmtRange(getRawCases(), AsCaseStmtWithSkippingNonCaseStmts());
}
static bool classof(const Stmt *S) {
@@ -48,6 +48,11 @@ class TypeMemberVisitor : public DeclVisitor<ImplClass, RetTy> {
return RetTy();
}
// These decls are disregarded.
RetTy visitPoundDiagnosticDecl(PoundDiagnosticDecl *D) {
return RetTy();
}
/// A convenience method to visit all the members.
void visitMembers(NominalTypeDecl *D) {
for (Decl *member : D->getMembers()) {
Copy path View file
@@ -755,6 +755,9 @@ class Parser {
ParserResult<IfConfigDecl> parseIfConfig(
llvm::function_ref<void(SmallVectorImpl<ASTNode> &, bool)> parseElements);
/// Parse a #error or #warning diagnostic.
ParserResult<PoundDiagnosticDecl> parseDeclPoundDiagnostic();
/// Parse a #line/#sourceLocation directive.
/// 'isLine = true' indicates parsing #line instead of #sourcelocation
ParserStatus parseLineDirective(bool isLine = false);
@@ -168,6 +168,10 @@ template <class T> class SILWitnessVisitor : public ASTVisitor<T> {
// We only care about the active members, which were already subsumed by the
// enclosing type.
}
void visitPoundDiagnosticDecl(PoundDiagnosticDecl *pdd) {
// We don't care about diagnostics at this stage.
}
};
} // end namespace swift
@@ -255,6 +255,8 @@ POUND_KEYWORD(keyPath)
POUND_KEYWORD(line)
POUND_KEYWORD(sourceLocation)
POUND_KEYWORD(selector)
POUND_KEYWORD(warning)
POUND_KEYWORD(error)
// Keywords prefixed with a '#' that are build configurations.
POUND_CONFIG(available)
Copy path View file
@@ -1098,6 +1098,16 @@ namespace {
PrintWithColorRAII(OS, ParenthesisColor) << ')';
}
void visitPoundDiagnosticDecl(PoundDiagnosticDecl *PDD) {
printCommon(PDD, "pound_diagnostic_decl");
auto kind = PDD->isError() ? "error" : "warning";
OS << " kind=" << kind << "\n";
Indent += 2;
printRec(PDD->getMessage());
Indent -= 2;
PrintWithColorRAII(OS, ParenthesisColor) << ')';
}
void visitPrecedenceGroupDecl(PrecedenceGroupDecl *PGD) {
printCommon(PGD, "precedence_group_decl ");
OS << PGD->getName() << "\n";
Copy path View file
@@ -1917,6 +1917,17 @@ void PrintAST::visitIfConfigDecl(IfConfigDecl *ICD) {
Printer << tok::pound_endif;
}
void PrintAST::visitPoundDiagnosticDecl(PoundDiagnosticDecl *PDD) {
/// TODO: Should we even print #error/#warning?
if (PDD->isError()) {
Printer << tok::pound_error;
} else {
Printer << tok::pound_warning;
}
Printer << "(\"" << PDD->getMessage()->getValue() << "\")";
}
void PrintAST::visitTypeAliasDecl(TypeAliasDecl *decl) {
printDocumentationComment(decl);
printAttributes(decl);
Copy path View file
@@ -881,6 +881,7 @@ ASTScope *ASTScope::createIfNeeded(const ASTScope *parent, Decl *decl) {
case DeclKind::Param:
case DeclKind::EnumElement:
case DeclKind::IfConfig:
case DeclKind::PoundDiagnostic:
case DeclKind::MissingMember:
// These declarations do not introduce scopes.
return nullptr;
Copy path View file
@@ -188,6 +188,11 @@ class Traversal : public ASTVisitor<Traversal, Expr*, Stmt*,
return false;
}
bool visitPoundDiagnosticDecl(PoundDiagnosticDecl *PDD) {
// By default, ignore #error/#warning.
return false;
}
bool visitOperatorDecl(OperatorDecl *OD) {
return false;
}
@@ -1476,7 +1481,8 @@ Stmt *Traversal::visitSwitchStmt(SwitchStmt *S) {
} else
return nullptr;
} else {
assert(isa<IfConfigDecl>(N.get<Decl*>()));
assert(isa<IfConfigDecl>(N.get<Decl*>()) ||
isa<PoundDiagnosticDecl>(N.get<Decl*>()));
if (doIt(N.get<Decl*>()))
return nullptr;
}
Copy path View file
@@ -125,6 +125,7 @@ DescriptiveDeclKind Decl::getDescriptiveKind() const {
TRIVIAL_KIND(EnumCase);
TRIVIAL_KIND(TopLevelCode);
TRIVIAL_KIND(IfConfig);
TRIVIAL_KIND(PoundDiagnostic);
TRIVIAL_KIND(PatternBinding);
TRIVIAL_KIND(PrecedenceGroup);
TRIVIAL_KIND(InfixOperator);
@@ -235,6 +236,7 @@ StringRef Decl::getDescriptiveKindName(DescriptiveDeclKind K) {
ENTRY(EnumCase, "case");
ENTRY(TopLevelCode, "top-level code");
ENTRY(IfConfig, "conditional block");
ENTRY(PoundDiagnostic, "diagnostic");
ENTRY(PatternBinding, "pattern binding");
ENTRY(Var, "var");
ENTRY(Param, "parameter");
@@ -769,6 +771,7 @@ ImportKind ImportDecl::getBestImportKind(const ValueDecl *VD) {
case DeclKind::PostfixOperator:
case DeclKind::EnumCase:
case DeclKind::IfConfig:
case DeclKind::PoundDiagnostic:
case DeclKind::PrecedenceGroup:
case DeclKind::MissingMember:
llvm_unreachable("not a ValueDecl");
@@ -1535,6 +1538,7 @@ bool ValueDecl::isDefinition() const {
case DeclKind::PrefixOperator:
case DeclKind::PostfixOperator:
case DeclKind::IfConfig:
case DeclKind::PoundDiagnostic:
case DeclKind::PrecedenceGroup:
case DeclKind::MissingMember:
assert(!isa<ValueDecl>(this));
@@ -1578,6 +1582,7 @@ bool ValueDecl::isInstanceMember() const {
case DeclKind::PrefixOperator:
case DeclKind::PostfixOperator:
case DeclKind::IfConfig:
case DeclKind::PoundDiagnostic:
case DeclKind::PrecedenceGroup:
case DeclKind::MissingMember:
llvm_unreachable("Not a ValueDecl");
Copy path View file
@@ -404,7 +404,8 @@ SwitchStmt *SwitchStmt::create(LabeledStmtInfo LabelInfo, SourceLoc SwitchLoc,
#ifndef NDEBUG
for (auto N : Cases)
assert((N.is<Stmt*>() && isa<CaseStmt>(N.get<Stmt*>())) ||
(N.is<Decl*>() && isa<IfConfigDecl>(N.get<Decl*>())));
(N.is<Decl*>() && (isa<IfConfigDecl>(N.get<Decl*>()) ||
isa<PoundDiagnosticDecl>(N.get<Decl*>()))));
#endif
void *p = C.Allocate(totalSizeToAlloc<ASTNode>(Cases.size()),
@@ -69,6 +69,7 @@ static bool declIsPrivate(const Decl *member) {
case DeclKind::EnumCase:
case DeclKind::TopLevelCode:
case DeclKind::IfConfig:
case DeclKind::PoundDiagnostic:
return true;
case DeclKind::Extension:
@@ -240,6 +241,7 @@ bool swift::emitReferenceDependencies(DiagnosticEngine &diags,
case DeclKind::PatternBinding:
case DeclKind::TopLevelCode:
case DeclKind::IfConfig:
case DeclKind::PoundDiagnostic:
// No action necessary.
break;
Copy path View file
@@ -548,6 +548,7 @@ CodeCompletionResult::getCodeCompletionDeclKind(const Decl *D) {
case DeclKind::EnumCase:
case DeclKind::TopLevelCode:
case DeclKind::IfConfig:
case DeclKind::PoundDiagnostic:
case DeclKind::MissingMember:
llvm_unreachable("not expecting such a declaration result");
case DeclKind::Module:
Copy path View file
@@ -1881,7 +1881,8 @@ void IRGenModule::emitGlobalDecl(Decl *D) {
case DeclKind::TypeAlias:
case DeclKind::GenericTypeParam:
case DeclKind::AssociatedType:
case DeclKind::IfConfig:
case DeclKind::IfConfig:
case DeclKind::PoundDiagnostic:
return;
case DeclKind::Enum:
@@ -3322,6 +3323,7 @@ void IRGenModule::emitNestedTypeDecls(DeclRange members) {
llvm_unreachable("decl not allowed in type context");
case DeclKind::IfConfig:
case DeclKind::PoundDiagnostic:
continue;
case DeclKind::PatternBinding:
Copy path View file
@@ -214,6 +214,7 @@ SymbolInfo index::getSymbolInfoForDecl(const Decl *D) {
case DeclKind::EnumCase:
case DeclKind::TopLevelCode:
case DeclKind::IfConfig:
case DeclKind::PoundDiagnostic:
case DeclKind::MissingMember:
case DeclKind::Module:
break;
Oops, something went wrong.
ProTip! Use n and p to navigate between commits in a pull request.