@@ -390,6 +390,39 @@ class alignas(8) PoundAvailableInfo final :
390390 bool isUnavailability () const { return _isUnavailability; }
391391};
392392
393+ // / An expression that guards execution based on whether the symbols for the
394+ // / declaration identified by the given expression are non-null at run-time, e.g.
395+ // /
396+ // / if #_hasSymbol(foo(_:)) { foo(42) }
397+ // /
398+ class PoundHasSymbolInfo final : public ASTAllocated<PoundHasSymbolInfo> {
399+ Expr *SymbolExpr;
400+
401+ SourceLoc PoundLoc;
402+ SourceLoc LParenLoc;
403+ SourceLoc RParenLoc;
404+
405+ PoundHasSymbolInfo (SourceLoc PoundLoc, SourceLoc LParenLoc, Expr *SymbolExpr,
406+ SourceLoc RParenLoc)
407+ : SymbolExpr(SymbolExpr), PoundLoc(PoundLoc), LParenLoc(LParenLoc),
408+ RParenLoc (RParenLoc){};
409+
410+ public:
411+ static PoundHasSymbolInfo *create (ASTContext &Ctx, SourceLoc PoundLoc,
412+ SourceLoc LParenLoc, Expr *SymbolExpr,
413+ SourceLoc RParenLoc);
414+
415+ Expr *getSymbolExpr () const { return SymbolExpr; }
416+ void setSymbolExpr (Expr *E) { SymbolExpr = E; }
417+
418+ SourceLoc getLParenLoc () const { return LParenLoc; }
419+ SourceLoc getRParenLoc () const { return RParenLoc; }
420+ SourceLoc getStartLoc () const { return PoundLoc; }
421+ SourceLoc getEndLoc () const { return RParenLoc; }
422+ SourceRange getSourceRange () const {
423+ return SourceRange (getStartLoc (), getEndLoc ());
424+ }
425+ };
393426
394427// / This represents an entry in an "if" or "while" condition. Pattern bindings
395428// / can bind any number of names in the pattern binding decl, and may have an
@@ -414,47 +447,55 @@ class alignas(1 << PatternAlignInBits) StmtConditionElement {
414447 // / to this as an 'implicit' pattern.
415448 Pattern *ThePattern = nullptr ;
416449
417- // / This is either the boolean condition, the initializer for a pattern
418- // / binding, or the #available information.
419- llvm::PointerUnion<PoundAvailableInfo*, Expr *> CondInitOrAvailable;
450+ // / This is either the boolean condition, the #available information, or
451+ // / the #_hasSymbol information.
452+ llvm::PointerUnion<Expr *, PoundAvailableInfo *, PoundHasSymbolInfo *>
453+ Condition;
420454
421455public:
422456 StmtConditionElement () {}
423- StmtConditionElement (SourceLoc IntroducerLoc, Pattern *ThePattern,
424- Expr *Init)
425- : IntroducerLoc (IntroducerLoc), ThePattern (ThePattern),
426- CondInitOrAvailable (Init) {}
427- StmtConditionElement (Expr *cond) : CondInitOrAvailable (cond) {}
457+ StmtConditionElement (SourceLoc IntroducerLoc, Pattern *ThePattern, Expr *Init)
458+ : IntroducerLoc (IntroducerLoc), ThePattern (ThePattern), Condition (Init) {}
459+ StmtConditionElement (Expr *cond) : Condition (cond) {}
460+
461+ StmtConditionElement (PoundAvailableInfo *Info) : Condition (Info) {}
462+
463+ StmtConditionElement (PoundHasSymbolInfo *Info) : Condition (Info) {}
428464
429- StmtConditionElement (PoundAvailableInfo *Info) : CondInitOrAvailable (Info) {}
430-
431465 SourceLoc getIntroducerLoc () const { return IntroducerLoc; }
432466 void setIntroducerLoc (SourceLoc loc) { IntroducerLoc = loc; }
433467
434468 // / ConditionKind - This indicates the sort of condition this is.
435469 enum ConditionKind {
436470 CK_Boolean,
437471 CK_PatternBinding,
438- CK_Availability
472+ CK_Availability,
473+ CK_HasSymbol,
439474 };
440475
441476 ConditionKind getKind () const {
442- if (ThePattern) return CK_PatternBinding;
443- return CondInitOrAvailable.is <Expr*>() ? CK_Boolean : CK_Availability;
477+ if (ThePattern)
478+ return CK_PatternBinding;
479+ if (Condition.is <Expr *>())
480+ return CK_Boolean;
481+ if (Condition.is <PoundAvailableInfo *>())
482+ return CK_Availability;
483+ assert (Condition.is <PoundHasSymbolInfo *>());
484+ return CK_HasSymbol;
444485 }
445486
446487 // / Boolean Condition Accessors.
447488 Expr *getBooleanOrNull () const {
448- return getKind () == CK_Boolean ? CondInitOrAvailable .get <Expr*>() : nullptr ;
489+ return getKind () == CK_Boolean ? Condition .get <Expr *>() : nullptr ;
449490 }
450491
451492 Expr *getBoolean () const {
452493 assert (getKind () == CK_Boolean && " Not a condition" );
453- return CondInitOrAvailable .get <Expr*>();
494+ return Condition .get <Expr *>();
454495 }
455496 void setBoolean (Expr *E) {
456497 assert (getKind () == CK_Boolean && " Not a condition" );
457- CondInitOrAvailable = E;
498+ Condition = E;
458499 }
459500
460501 // / Pattern Binding Accessors.
@@ -474,22 +515,33 @@ class alignas(1 << PatternAlignInBits) StmtConditionElement {
474515
475516 Expr *getInitializer () const {
476517 assert (getKind () == CK_PatternBinding && " Not a pattern binding condition" );
477- return CondInitOrAvailable .get <Expr*>();
518+ return Condition .get <Expr *>();
478519 }
479520 void setInitializer (Expr *E) {
480521 assert (getKind () == CK_PatternBinding && " Not a pattern binding condition" );
481- CondInitOrAvailable = E;
522+ Condition = E;
482523 }
483524
484525 // Availability Accessors
485526 PoundAvailableInfo *getAvailability () const {
486527 assert (getKind () == CK_Availability && " Not an #available condition" );
487- return CondInitOrAvailable .get <PoundAvailableInfo*>();
528+ return Condition .get <PoundAvailableInfo *>();
488529 }
489530
490531 void setAvailability (PoundAvailableInfo *Info) {
491532 assert (getKind () == CK_Availability && " Not an #available condition" );
492- CondInitOrAvailable = Info;
533+ Condition = Info;
534+ }
535+
536+ // #_hasSymbol Accessors
537+ PoundHasSymbolInfo *getHasSymbolInfo () const {
538+ assert (getKind () == CK_HasSymbol && " Not a #_hasSymbol condition" );
539+ return Condition.get <PoundHasSymbolInfo *>();
540+ }
541+
542+ void setHasSymbolInfo (PoundHasSymbolInfo *Info) {
543+ assert (getKind () == CK_HasSymbol && " Not a #_hasSymbol condition" );
544+ Condition = Info;
493545 }
494546
495547 SourceLoc getStartLoc () const ;
0 commit comments