Skip to content

Commit bd70bee

Browse files
authored
Merge pull request swiftlang#36474 from beccadax/objc-behave
[NFC] Use behavior limits to control @objc errors
2 parents 4bffcac + 16630f2 commit bd70bee

File tree

5 files changed

+277
-237
lines changed

5 files changed

+277
-237
lines changed

include/swift/AST/DiagnosticEngine.h

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include "llvm/Support/Allocator.h"
3030
#include "llvm/Support/FileSystem.h"
3131
#include "llvm/Support/Path.h"
32+
#include "llvm/Support/SaveAndRestore.h"
3233
#include "llvm/Support/VersionTuple.h"
3334

3435
namespace swift {
@@ -640,6 +641,8 @@ namespace swift {
640641
/// Track which diagnostics should be ignored.
641642
llvm::BitVector ignoredDiagnostics;
642643

644+
friend class DiagnosticStateRAII;
645+
643646
public:
644647
DiagnosticState();
645648

@@ -740,6 +743,7 @@ namespace swift {
740743
friend class InFlightDiagnostic;
741744
friend class DiagnosticTransaction;
742745
friend class CompoundDiagnosticTransaction;
746+
friend class DiagnosticStateRAII;
743747

744748
public:
745749
explicit DiagnosticEngine(SourceManager &SourceMgr)
@@ -1053,6 +1057,33 @@ namespace swift {
10531057
}
10541058
};
10551059

1060+
/// Remember details about the state of a diagnostic engine and restore them
1061+
/// when the object is destroyed.
1062+
///
1063+
/// Diagnostic engines contain state about the most recent diagnostic emitted
1064+
/// which influences subsequent emissions; in particular, if you try to emit
1065+
/// a note and the previous diagnostic was ignored, the note will be ignored
1066+
/// too. This can be a problem in code structured like:
1067+
///
1068+
/// D->diagnose(diag::an_error);
1069+
/// if (conditionWhichMightEmitDiagnostics())
1070+
/// D->diagnose(diag::a_note); // might be affected by diagnostics from
1071+
/// // conditionWhichMightEmitDiagnostics()!
1072+
///
1073+
/// To prevent this, functions which are called for their return values but
1074+
/// may emit diagnostics as a side effect can use \c DiagnosticStateRAII to
1075+
/// ensure that their changes to diagnostic engine state don't leak out and
1076+
/// affect the caller's diagnostics.
1077+
class DiagnosticStateRAII {
1078+
llvm::SaveAndRestore<DiagnosticBehavior> previousBehavior;
1079+
1080+
public:
1081+
DiagnosticStateRAII(DiagnosticEngine &diags)
1082+
: previousBehavior(diags.state.previousBehavior) {}
1083+
1084+
~DiagnosticStateRAII() {}
1085+
};
1086+
10561087
class BufferIndirectlyCausingDiagnosticRAII {
10571088
private:
10581089
DiagnosticEngine &Diags;

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -902,27 +902,30 @@ static bool isConcurrentValueType(const DeclContext *dc, Type type) {
902902

903903
static bool diagnoseNonConcurrentParameter(
904904
SourceLoc loc, ConcurrentReferenceKind refKind, ConcreteDeclRef declRef,
905-
ParamDecl *param, Type paramType) {
905+
ParamDecl *param, Type paramType, DiagnosticBehavior behavior) {
906906
ASTContext &ctx = declRef.getDecl()->getASTContext();
907-
ctx.Diags.diagnose(loc, diag::non_concurrent_param_type, paramType);
907+
ctx.Diags.diagnose(loc, diag::non_concurrent_param_type, paramType)
908+
.limitBehavior(behavior);
908909
return false;
909910
}
910911

911912
static bool diagnoseNonConcurrentResult(
912913
SourceLoc loc, ConcurrentReferenceKind refKind, ConcreteDeclRef declRef,
913-
Type resultType) {
914+
Type resultType, DiagnosticBehavior behavior) {
914915
ASTContext &ctx = declRef.getDecl()->getASTContext();
915-
ctx.Diags.diagnose(loc, diag::non_concurrent_result_type, resultType);
916+
ctx.Diags.diagnose(loc, diag::non_concurrent_result_type, resultType)
917+
.limitBehavior(behavior);
916918
return false;
917919
}
918920

919921
static bool diagnoseNonConcurrentProperty(
920922
SourceLoc loc, ConcurrentReferenceKind refKind, VarDecl *var,
921-
Type propertyType) {
923+
Type propertyType, DiagnosticBehavior behavior) {
922924
ASTContext &ctx = var->getASTContext();
923925
ctx.Diags.diagnose(loc, diag::non_concurrent_property_type,
924926
var->getDescriptiveKind(), var->getName(),
925-
propertyType, var->isLocalCapture());
927+
propertyType, var->isLocalCapture())
928+
.limitBehavior(behavior);
926929
return false;
927930
}
928931

@@ -935,7 +938,7 @@ static bool shouldDiagnoseNonConcurrentValueViolations(
935938

936939
bool swift::diagnoseNonConcurrentTypesInReference(
937940
ConcreteDeclRef declRef, const DeclContext *dc, SourceLoc loc,
938-
ConcurrentReferenceKind refKind) {
941+
ConcurrentReferenceKind refKind, DiagnosticBehavior behavior) {
939942
// Bail out immediately if we aren't supposed to do this checking.
940943
if (!shouldDiagnoseNonConcurrentValueViolations(dc->getASTContext().LangOpts))
941944
return false;
@@ -947,15 +950,16 @@ bool swift::diagnoseNonConcurrentTypesInReference(
947950
Type paramType = param->getInterfaceType().subst(subs);
948951
if (!isConcurrentValueType(dc, paramType)) {
949952
return diagnoseNonConcurrentParameter(
950-
loc, refKind, declRef, param, paramType);
953+
loc, refKind, declRef, param, paramType, behavior);
951954
}
952955
}
953956

954957
// Check the result type of a function.
955958
if (auto func = dyn_cast<FuncDecl>(function)) {
956959
Type resultType = func->getResultInterfaceType().subst(subs);
957960
if (!isConcurrentValueType(dc, resultType)) {
958-
return diagnoseNonConcurrentResult(loc, refKind, declRef, resultType);
961+
return diagnoseNonConcurrentResult(loc, refKind, declRef, resultType,
962+
behavior);
959963
}
960964
}
961965

@@ -967,7 +971,8 @@ bool swift::diagnoseNonConcurrentTypesInReference(
967971
? var->getType()
968972
: var->getValueInterfaceType().subst(subs);
969973
if (!isConcurrentValueType(dc, propertyType)) {
970-
return diagnoseNonConcurrentProperty(loc, refKind, var, propertyType);
974+
return diagnoseNonConcurrentProperty(loc, refKind, var, propertyType,
975+
behavior);
971976
}
972977
}
973978

@@ -976,14 +981,15 @@ bool swift::diagnoseNonConcurrentTypesInReference(
976981
Type paramType = param->getInterfaceType().subst(subs);
977982
if (!isConcurrentValueType(dc, paramType)) {
978983
return diagnoseNonConcurrentParameter(
979-
loc, refKind, declRef, param, paramType);
984+
loc, refKind, declRef, param, paramType, behavior);
980985
}
981986
}
982987

983988
// Check the element type of a subscript.
984989
Type resultType = subscript->getElementInterfaceType().subst(subs);
985990
if (!isConcurrentValueType(dc, resultType)) {
986-
return diagnoseNonConcurrentResult(loc, refKind, declRef, resultType);
991+
return diagnoseNonConcurrentResult(loc, refKind, declRef, resultType,
992+
behavior);
987993
}
988994

989995
return false;

lib/Sema/TypeCheckConcurrency.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#define SWIFT_SEMA_TYPECHECKCONCURRENCY_H
1919

2020
#include "swift/AST/ConcreteDeclRef.h"
21+
#include "swift/AST/DiagnosticEngine.h"
2122
#include "swift/AST/Type.h"
2223
#include <cassert>
2324

@@ -205,7 +206,8 @@ bool contextUsesConcurrencyFeatures(const DeclContext *dc);
205206
/// \returns true if an problem was detected, false otherwise.
206207
bool diagnoseNonConcurrentTypesInReference(
207208
ConcreteDeclRef declRef, const DeclContext *dc, SourceLoc loc,
208-
ConcurrentReferenceKind refKind);
209+
ConcurrentReferenceKind refKind,
210+
DiagnosticBehavior behavior = DiagnosticBehavior::Unspecified);
209211

210212
/// How the concurrent value check should be performed.
211213
enum class ConcurrentValueCheck {

0 commit comments

Comments
 (0)