STATIC bool
S_reginclass(pTHX_ regexp * const prog, const regnode * const n, const U8* const p, const U8* const p_end, const bool utf8_target)
{
    dVAR;
    const char flags = ANYOF_FLAGS(n);
    bool match = FALSE;
    UV c = *p;

    PERL_ARGS_ASSERT_REGINCLASS;

    /* If c is not already the code point, get it.  Note that
     * UTF8_IS_INVARIANT() works even if not in UTF-8 */
    if (! UTF8_IS_INVARIANT(c) && utf8_target) {
        STRLEN c_len = 0;
	c = utf8n_to_uvchr(p, p_end - p, &c_len,
		(UTF8_ALLOW_DEFAULT & UTF8_ALLOW_ANYUV)
		| UTF8_ALLOW_FFFF | UTF8_CHECK_ONLY);
		/* see [perl #37836] for UTF8_ALLOW_ANYUV; [perl #38293] for
		 * UTF8_ALLOW_FFFF */
	if (c_len == (STRLEN)-1)
	    Perl_croak(aTHX_ "Malformed UTF-8 character (fatal)");
        if (c > 255 && OP(n) == ANYOFL && ! (flags & ANYOF_LOC_REQ_UTF8)) {
            _CHECK_AND_OUTPUT_WIDE_LOCALE_CP_MSG(c);
        }
    }

    /* If this character is potentially in the bitmap, check it */
    if (c < NUM_ANYOF_CODE_POINTS) {
	if (ANYOF_BITMAP_TEST(n, c))
	    match = TRUE;
	else if ((flags
                & ANYOF_SHARED_d_MATCHES_ALL_NON_UTF8_NON_ASCII_non_d_WARN_SUPER)
                  && OP(n) == ANYOFD
		  && ! utf8_target
		  && ! isASCII(c))
	{
	    match = TRUE;
	}
	else if (flags & ANYOF_LOCALE_FLAGS) {
	    if ((flags & ANYOF_LOC_FOLD)
                && c < 256
		&& ANYOF_BITMAP_TEST(n, PL_fold_locale[c]))
            {
                match = TRUE;
            }
            else if (ANYOF_POSIXL_TEST_ANY_SET(n)
                     && c < 256
            ) {

                /* The data structure is arranged so bits 0, 2, 4, ... are set
                 * if the class includes the Posix character class given by
                 * bit/2; and 1, 3, 5, ... are set if the class includes the
                 * complemented Posix class given by int(bit/2).  So we loop
                 * through the bits, each time changing whether we complement
                 * the result or not.  Suppose for the sake of illustration
                 * that bits 0-3 mean respectively, \w, \W, \s, \S.  If bit 0
                 * is set, it means there is a match for this ANYOF node if the
                 * character is in the class given by the expression (0 / 2 = 0
                 * = \w).  If it is in that class, isFOO_lc() will return 1,
                 * and since 'to_complement' is 0, the result will stay TRUE,
                 * and we exit the loop.  Suppose instead that bit 0 is 0, but
                 * bit 1 is 1.  That means there is a match if the character
                 * matches \W.  We won't bother to call isFOO_lc() on bit 0,
                 * but will on bit 1.  On the second iteration 'to_complement'
                 * will be 1, so the exclusive or will reverse things, so we
                 * are testing for \W.  On the third iteration, 'to_complement'
                 * will be 0, and we would be testing for \s; the fourth
                 * iteration would test for \S, etc.
                 *
                 * Note that this code assumes that all the classes are closed
                 * under folding.  For example, if a character matches \w, then
                 * its fold does too; and vice versa.  This should be true for
                 * any well-behaved locale for all the currently defined Posix
                 * classes, except for :lower: and :upper:, which are handled
                 * by the pseudo-class :cased: which matches if either of the
                 * other two does.  To get rid of this assumption, an outer
                 * loop could be used below to iterate over both the source
                 * character, and its fold (if different) */

                int count = 0;
                int to_complement = 0;

                while (count < ANYOF_MAX) {
                    if (ANYOF_POSIXL_TEST(n, count)
                        && to_complement ^ cBOOL(isFOO_lc(count/2, (U8) c)))
                    {
                        match = TRUE;
                        break;
                    }
                    count++;
                    to_complement ^= 1;
                }
	    }
	}
    }


    /* If the bitmap didn't (or couldn't) match, and something outside the
     * bitmap could match, try that. */
    if (!match) {
	if (c >= NUM_ANYOF_CODE_POINTS
            && (flags & ANYOF_MATCHES_ALL_ABOVE_BITMAP))
        {
	    match = TRUE;	/* Everything above the bitmap matches */
	}
	else if ((flags & ANYOF_HAS_NONBITMAP_NON_UTF8_MATCHES)
		  || (utf8_target && (flags & ANYOF_HAS_UTF8_NONBITMAP_MATCHES))
                  || ((flags & ANYOF_LOC_FOLD)
                       && IN_UTF8_CTYPE_LOCALE
                       && ARG(n) != ANYOF_ONLY_HAS_BITMAP))
        {
            SV* only_utf8_locale = NULL;
	    SV * const sw = _get_regclass_nonbitmap_data(prog, n, TRUE, 0,
                                                       &only_utf8_locale, NULL);
	    if (sw) {
                U8 utf8_buffer[2];
		U8 * utf8_p;
		if (utf8_target) {
		    utf8_p = (U8 *) p;
		} else { /* Convert to utf8 */
		    utf8_p = utf8_buffer;
                    append_utf8_from_native_byte(*p, &utf8_p);
		    utf8_p = utf8_buffer;
		}

		if (swash_fetch(sw, utf8_p, TRUE)) {
		    match = TRUE;
                }
	    }
            if (! match && only_utf8_locale && IN_UTF8_CTYPE_LOCALE) {
                match = _invlist_contains_cp(only_utf8_locale, c);
            }
	}

        if (UNICODE_IS_SUPER(c)
            && (flags
               & ANYOF_SHARED_d_MATCHES_ALL_NON_UTF8_NON_ASCII_non_d_WARN_SUPER)
            && OP(n) != ANYOFD
            && ckWARN_d(WARN_NON_UNICODE))
        {
            Perl_warner(aTHX_ packWARN(WARN_NON_UNICODE),
                "Matched non-Unicode code point 0x%04"UVXf" against Unicode property; may not be portable", c);
        }
    }

#if ANYOF_INVERT != 1
    /* Depending on compiler optimization cBOOL takes time, so if don't have to
     * use it, don't */
#   error ANYOF_INVERT needs to be set to 1, or guarded with cBOOL below,
#endif

    /* The xor complements the return if to invert: 1^1 = 0, 1^0 = 1 */
    return (flags & ANYOF_INVERT) ^ match;