re PR c++/37208 (C++0x deleted functions and SFINAE)

PR c++/37208
        * call.c (build_over_call): Make =delete work with SFINAE.
        * class.c (resolve_address_of_overloaded_function): Likewise.

        * cp-tree.h (struct lang_decl_flags): Rename threadprivate_p to
        threadprivate_or_deleted_p.
        (CP_DECL_THREADPRIVATE_P): Adjust.
        (DECL_DELETED_FN): Likewise.
        (SD_UNINITIALIZED, SD_INITIALIZED, SD_DEFAULTED): New macros.
        (SD_DELETED): New macro.
        * parser.c (cp_parser_init_declarator): Use them.
        * decl.c (start_decl): Use them.

        * decl2.c (mark_used): Give =deleted error even in sizeof.

        * typeck2.c (check_narrowing): Downgrade narrowing error to
        permerror.

From-SVN: r139926
This commit is contained in:
Jason Merrill 2008-09-03 00:10:27 -04:00 committed by Jason Merrill
parent a63068b6dd
commit 4ad610c978
9 changed files with 84 additions and 23 deletions

View File

@ -1,3 +1,23 @@
2008-09-02 Jason Merrill <jason@redhat.com>
PR c++/37208
* call.c (build_over_call): Make =delete work with SFINAE.
* class.c (resolve_address_of_overloaded_function): Likewise.
* cp-tree.h (struct lang_decl_flags): Rename threadprivate_p to
threadprivate_or_deleted_p.
(CP_DECL_THREADPRIVATE_P): Adjust.
(DECL_DELETED_FN): Likewise.
(SD_UNINITIALIZED, SD_INITIALIZED, SD_DEFAULTED): New macros.
(SD_DELETED): New macro.
* parser.c (cp_parser_init_declarator): Use them.
* decl.c (start_decl): Use them.
* decl2.c (mark_used): Give =deleted error even in sizeof.
* typeck2.c (check_narrowing): Downgrade narrowing error to
permerror.
2008-09-02 Aldy Hernandez <aldyh@redhat.com> 2008-09-02 Aldy Hernandez <aldyh@redhat.com>
* typeck.c (build_array_ref): Use new location argument. * typeck.c (build_array_ref): Use new location argument.

View File

@ -5119,6 +5119,10 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
joust (cand, w->loser, 1); joust (cand, w->loser, 1);
} }
/* Make =delete work with SFINAE. */
if (DECL_DELETED_FN (fn) && !(complain & tf_error))
return error_mark_node;
if (DECL_FUNCTION_MEMBER_P (fn)) if (DECL_FUNCTION_MEMBER_P (fn))
{ {
/* If FN is a template function, two cases must be considered. /* If FN is a template function, two cases must be considered.

View File

@ -6185,6 +6185,10 @@ resolve_address_of_overloaded_function (tree target_type,
function will be marked as used at this point. */ function will be marked as used at this point. */
if (!(flags & tf_conv)) if (!(flags & tf_conv))
{ {
/* Make =delete work with SFINAE. */
if (DECL_DELETED_FN (fn) && !(flags & tf_error))
return error_mark_node;
mark_used (fn); mark_used (fn);
/* We could not check access when this expression was originally /* We could not check access when this expression was originally
created since we did not know at that time to which function created since we did not know at that time to which function

View File

@ -1629,7 +1629,7 @@ struct lang_decl_flags GTY(())
unsigned this_thunk_p : 1; unsigned this_thunk_p : 1;
unsigned repo_available_p : 1; unsigned repo_available_p : 1;
unsigned hidden_friend_p : 1; unsigned hidden_friend_p : 1;
unsigned threadprivate_p : 1; unsigned threadprivate_or_deleted_p : 1;
unsigned defaulted_p : 1; unsigned defaulted_p : 1;
union lang_decl_u { union lang_decl_u {
@ -2645,11 +2645,11 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter)
/* Nonzero if DECL has been declared threadprivate by /* Nonzero if DECL has been declared threadprivate by
#pragma omp threadprivate. */ #pragma omp threadprivate. */
#define CP_DECL_THREADPRIVATE_P(DECL) \ #define CP_DECL_THREADPRIVATE_P(DECL) \
(DECL_LANG_SPECIFIC (VAR_DECL_CHECK (DECL))->decl_flags.threadprivate_p) (DECL_LANG_SPECIFIC (VAR_DECL_CHECK (DECL))->decl_flags.threadprivate_or_deleted_p)
/* Nonzero if DECL was declared with '= delete'. */ /* Nonzero if DECL was declared with '= delete'. */
#define DECL_DELETED_FN(DECL) \ #define DECL_DELETED_FN(DECL) \
(DECL_LANG_SPECIFIC (FUNCTION_DECL_CHECK (DECL))->decl_flags.threadprivate_p) (DECL_LANG_SPECIFIC (FUNCTION_DECL_CHECK (DECL))->decl_flags.threadprivate_or_deleted_p)
/* Nonzero if DECL was declared with '= default'. */ /* Nonzero if DECL was declared with '= default'. */
#define DECL_DEFAULTED_FN(DECL) \ #define DECL_DEFAULTED_FN(DECL) \
@ -3863,6 +3863,12 @@ enum overload_flags { NO_SPECIAL = 0, DTOR_FLAG, OP_FLAG, TYPENAME_FLAG };
#define SF_INCLASS_INLINE 2 /* The function is an inline, defined #define SF_INCLASS_INLINE 2 /* The function is an inline, defined
in the class body. */ in the class body. */
/* Used with start_decl's initialized parameter. */
#define SD_UNINITIALIZED 0
#define SD_INITIALIZED 1
#define SD_DEFAULTED 2
#define SD_DELETED 3
/* Returns nonzero iff TYPE1 and TYPE2 are the same type, or if TYPE2 /* Returns nonzero iff TYPE1 and TYPE2 are the same type, or if TYPE2
is derived from TYPE1, or if TYPE2 is a pointer (reference) to a is derived from TYPE1, or if TYPE2 is a pointer (reference) to a
class derived from the type pointed to (referred to) by TYPE1. */ class derived from the type pointed to (referred to) by TYPE1. */

View File

@ -3969,14 +3969,14 @@ groktypename (cp_decl_specifier_seq *type_specifiers,
grokfield.) The DECL corresponding to the DECLARATOR is returned. grokfield.) The DECL corresponding to the DECLARATOR is returned.
If an error occurs, the error_mark_node is returned instead. If an error occurs, the error_mark_node is returned instead.
DECLSPECS are the decl-specifiers for the declaration. INITIALIZED is 1 DECLSPECS are the decl-specifiers for the declaration. INITIALIZED is
if an explicit initializer is present, or 2 for an explicitly defaulted SD_INITIALIZED if an explicit initializer is present, or SD_DEFAULTED
function, or 3 for an explicitly deleted function, but 0 if this is a for an explicitly defaulted function, or SD_DELETED for an explicitly
variable implicitly initialized via a default constructor. ATTRIBUTES deleted function, but 0 (SD_UNINITIALIZED) if this is a variable
and PREFIX_ATTRIBUTES are GNU attributes associated with this implicitly initialized via a default constructor. ATTRIBUTES and
declaration. *PUSHED_SCOPE_P is set to the scope entered in this PREFIX_ATTRIBUTES are GNU attributes associated with this declaration.
function, if any; if set, the caller is responsible for calling *PUSHED_SCOPE_P is set to the scope entered in this function, if any; if
pop_scope. */ set, the caller is responsible for calling pop_scope. */
tree tree
start_decl (const cp_declarator *declarator, start_decl (const cp_declarator *declarator,
@ -4034,7 +4034,7 @@ start_decl (const cp_declarator *declarator,
return error_mark_node; return error_mark_node;
case FUNCTION_DECL: case FUNCTION_DECL:
if (initialized == 3) if (initialized == SD_DELETED)
/* We'll handle the rest of the semantics later, but we need to /* We'll handle the rest of the semantics later, but we need to
set this now so it's visible to duplicate_decls. */ set this now so it's visible to duplicate_decls. */
DECL_DELETED_FN (decl) = 1; DECL_DELETED_FN (decl) = 1;

View File

@ -3767,6 +3767,12 @@ mark_used (tree decl)
TREE_USED (decl) = 1; TREE_USED (decl) = 1;
if (DECL_CLONED_FUNCTION_P (decl)) if (DECL_CLONED_FUNCTION_P (decl))
TREE_USED (DECL_CLONED_FUNCTION (decl)) = 1; TREE_USED (DECL_CLONED_FUNCTION (decl)) = 1;
if (TREE_CODE (decl) == FUNCTION_DECL
&& DECL_DELETED_FN (decl))
{
error ("deleted function %q+D", decl);
error ("used here");
}
/* If we don't need a value, then we don't need to synthesize DECL. */ /* If we don't need a value, then we don't need to synthesize DECL. */
if (skip_evaluation) if (skip_evaluation)
return; return;
@ -3830,12 +3836,6 @@ mark_used (tree decl)
/* If we've already synthesized the method we don't need to /* If we've already synthesized the method we don't need to
do the instantiation test below. */ do the instantiation test below. */
} }
else if (TREE_CODE (decl) == FUNCTION_DECL
&& DECL_DELETED_FN (decl))
{
error ("deleted function %q+D", decl);
error ("used here");
}
else if ((DECL_NON_THUNK_FUNCTION_P (decl) || TREE_CODE (decl) == VAR_DECL) else if ((DECL_NON_THUNK_FUNCTION_P (decl) || TREE_CODE (decl) == VAR_DECL)
&& DECL_LANG_SPECIFIC (decl) && DECL_TEMPLATE_INFO (decl) && DECL_LANG_SPECIFIC (decl) && DECL_TEMPLATE_INFO (decl)
&& (!DECL_EXPLICIT_INSTANTIATION (decl) && (!DECL_EXPLICIT_INSTANTIATION (decl)

View File

@ -12610,7 +12610,7 @@ cp_parser_init_declarator (cp_parser* parser,
|| token->type == CPP_OPEN_PAREN || token->type == CPP_OPEN_PAREN
|| token->type == CPP_OPEN_BRACE) || token->type == CPP_OPEN_BRACE)
{ {
is_initialized = 1; is_initialized = SD_INITIALIZED;
initialization_kind = token->type; initialization_kind = token->type;
if (token->type == CPP_EQ if (token->type == CPP_EQ
@ -12618,9 +12618,9 @@ cp_parser_init_declarator (cp_parser* parser,
{ {
cp_token *t2 = cp_lexer_peek_nth_token (parser->lexer, 2); cp_token *t2 = cp_lexer_peek_nth_token (parser->lexer, 2);
if (t2->keyword == RID_DEFAULT) if (t2->keyword == RID_DEFAULT)
is_initialized = 2; is_initialized = SD_DEFAULTED;
else if (t2->keyword == RID_DELETE) else if (t2->keyword == RID_DELETE)
is_initialized = 3; is_initialized = SD_DELETED;
} }
} }
else else
@ -12633,7 +12633,7 @@ cp_parser_init_declarator (cp_parser* parser,
cp_parser_error (parser, "expected initializer"); cp_parser_error (parser, "expected initializer");
return error_mark_node; return error_mark_node;
} }
is_initialized = 0; is_initialized = SD_UNINITIALIZED;
initialization_kind = CPP_EOF; initialization_kind = CPP_EOF;
} }

View File

@ -704,7 +704,8 @@ check_narrowing (tree type, tree init)
} }
if (!ok) if (!ok)
error ("narrowing conversion of %qE to %qT inside { }", init, type); permerror (input_location, "narrowing conversion of %qE to %qT inside { }",
init, type);
} }
/* Process the initializer INIT for a variable of type TYPE, emitting /* Process the initializer INIT for a variable of type TYPE, emitting

View File

@ -0,0 +1,26 @@
// PR c++/37208: SFINAE and deleted functions.
// { dg-options "-std=c++0x" }
// { dg-do compile }
template<int> struct A { };
template<typename T>
int& int_if_addable(A<sizeof((*(T*)0) + (*(T*)0))>*);
template<typename T>
float& int_if_addable(...);
struct X { };
struct Y { };
Y operator+(Y, Y);
struct Z { };
Z operator+(Z, Z) = delete;
void f()
{
float& x = int_if_addable<X>(0);
int& y = int_if_addable<Y>(0);
float& z = int_if_addable<Z>(0);
}