mirror of
https://github.com/intel/llvm.git
synced 2026-02-08 00:50:03 +08:00
[c++1z] Most of N4268 (allow constant evaluation for non-type template arguments).
We don't yet support pointer-to-member template arguments that have undergone pointer-to-member conversions, mostly because we don't have a mangling for them yet. llvm-svn: 222807
This commit is contained in:
@@ -64,6 +64,9 @@ def err_typecheck_converted_constant_expression : Error<
|
||||
"value of type %0 is not implicitly convertible to %1">;
|
||||
def err_typecheck_converted_constant_expression_disallowed : Error<
|
||||
"conversion from %0 to %1 is not allowed in a converted constant expression">;
|
||||
def err_typecheck_converted_constant_expression_indirect : Error<
|
||||
"conversion from %0 to %1 in converted constant expression would "
|
||||
"bind reference to a temporary">;
|
||||
def err_expr_not_cce : Error<
|
||||
"%select{case value|enumerator value|non-type template argument|array size}0 "
|
||||
"is not a constant expression">;
|
||||
@@ -3293,6 +3296,10 @@ def err_template_arg_wrongtype_null_constant : Error<
|
||||
def err_deduced_non_type_template_arg_type_mismatch : Error<
|
||||
"deduced non-type template argument does not have the same type as the "
|
||||
"its corresponding template parameter%diff{ ($ vs $)|}0,1">;
|
||||
def err_non_type_template_arg_subobject : Error<
|
||||
"non-type template argument refers to subobject '%0'">;
|
||||
def err_non_type_template_arg_addr_label_diff : Error<
|
||||
"template argument / label address difference / what did you expect?">;
|
||||
def err_template_arg_not_convertible : Error<
|
||||
"non-type template argument of type %0 cannot be converted to a value "
|
||||
"of type %1">;
|
||||
@@ -3344,6 +3351,9 @@ def err_template_arg_not_object_or_func : Error<
|
||||
"non-type template argument does not refer to an object or function">;
|
||||
def err_template_arg_not_pointer_to_member_form : Error<
|
||||
"non-type template argument is not a pointer to member constant">;
|
||||
def err_template_arg_member_ptr_base_derived_not_supported : Error<
|
||||
"sorry, non-type template argument of pointer-to-member type %1 that refers "
|
||||
"to member %q0 of a different class is not supported yet">;
|
||||
def ext_template_arg_extra_parens : ExtWarn<
|
||||
"address non-type template argument cannot be surrounded by parentheses">;
|
||||
def warn_cxx98_compat_template_arg_extra_parens : Warning<
|
||||
|
||||
@@ -2148,6 +2148,8 @@ public:
|
||||
};
|
||||
ExprResult CheckConvertedConstantExpression(Expr *From, QualType T,
|
||||
llvm::APSInt &Value, CCEKind CCE);
|
||||
ExprResult CheckConvertedConstantExpression(Expr *From, QualType T,
|
||||
APValue &Value, CCEKind CCE);
|
||||
|
||||
/// \brief Abstract base class used to perform a contextual implicit
|
||||
/// conversion from an expression to any type passing a filter.
|
||||
|
||||
@@ -2780,10 +2780,29 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
|
||||
// Perform the second implicit conversion
|
||||
switch (SCS.Second) {
|
||||
case ICK_Identity:
|
||||
// If both sides are functions (or pointers/references to them), there could
|
||||
// be incompatible exception declarations.
|
||||
if (CheckExceptionSpecCompatibility(From, ToType))
|
||||
return ExprError();
|
||||
// C++ [except.spec]p5:
|
||||
// [For] assignment to and initialization of pointers to functions,
|
||||
// pointers to member functions, and references to functions: the
|
||||
// target entity shall allow at least the exceptions allowed by the
|
||||
// source value in the assignment or initialization.
|
||||
switch (Action) {
|
||||
case AA_Assigning:
|
||||
case AA_Initializing:
|
||||
// Note, function argument passing and returning are initialization.
|
||||
case AA_Passing:
|
||||
case AA_Returning:
|
||||
case AA_Sending:
|
||||
case AA_Passing_CFAudited:
|
||||
if (CheckExceptionSpecCompatibility(From, ToType))
|
||||
return ExprError();
|
||||
break;
|
||||
|
||||
case AA_Casting:
|
||||
case AA_Converting:
|
||||
// Casts and implicit conversions are not initialization, so are not
|
||||
// checked for exception specification mismatches.
|
||||
break;
|
||||
}
|
||||
// Nothing else to do.
|
||||
break;
|
||||
|
||||
|
||||
@@ -4894,41 +4894,51 @@ static bool CheckConvertedConstantConversions(Sema &S,
|
||||
// conversions are fine.
|
||||
switch (SCS.Second) {
|
||||
case ICK_Identity:
|
||||
case ICK_NoReturn_Adjustment:
|
||||
case ICK_Integral_Promotion:
|
||||
case ICK_Integral_Conversion:
|
||||
case ICK_Zero_Event_Conversion:
|
||||
case ICK_Integral_Conversion: // Narrowing conversions are checked elsewhere.
|
||||
return true;
|
||||
|
||||
case ICK_Boolean_Conversion:
|
||||
// Conversion from an integral or unscoped enumeration type to bool is
|
||||
// classified as ICK_Boolean_Conversion, but it's also an integral
|
||||
// conversion, so it's permitted in a converted constant expression.
|
||||
// classified as ICK_Boolean_Conversion, but it's also arguably an integral
|
||||
// conversion, so we allow it in a converted constant expression.
|
||||
//
|
||||
// FIXME: Per core issue 1407, we should not allow this, but that breaks
|
||||
// a lot of popular code. We should at least add a warning for this
|
||||
// (non-conforming) extension.
|
||||
return SCS.getFromType()->isIntegralOrUnscopedEnumerationType() &&
|
||||
SCS.getToType(2)->isBooleanType();
|
||||
|
||||
case ICK_Pointer_Conversion:
|
||||
case ICK_Pointer_Member:
|
||||
// C++1z: null pointer conversions and null member pointer conversions are
|
||||
// only permitted if the source type is std::nullptr_t.
|
||||
return SCS.getFromType()->isNullPtrType();
|
||||
|
||||
case ICK_Floating_Promotion:
|
||||
case ICK_Complex_Promotion:
|
||||
case ICK_Floating_Conversion:
|
||||
case ICK_Complex_Conversion:
|
||||
case ICK_Floating_Integral:
|
||||
case ICK_Compatible_Conversion:
|
||||
case ICK_Derived_To_Base:
|
||||
case ICK_Vector_Conversion:
|
||||
case ICK_Vector_Splat:
|
||||
case ICK_Complex_Real:
|
||||
case ICK_Block_Pointer_Conversion:
|
||||
case ICK_TransparentUnionConversion:
|
||||
case ICK_Writeback_Conversion:
|
||||
case ICK_Zero_Event_Conversion:
|
||||
return false;
|
||||
|
||||
case ICK_Lvalue_To_Rvalue:
|
||||
case ICK_Array_To_Pointer:
|
||||
case ICK_Function_To_Pointer:
|
||||
case ICK_NoReturn_Adjustment:
|
||||
llvm_unreachable("found a first conversion kind in Second");
|
||||
|
||||
case ICK_Qualification:
|
||||
case ICK_Compatible_Conversion:
|
||||
case ICK_Vector_Conversion:
|
||||
case ICK_Vector_Splat:
|
||||
case ICK_Derived_To_Base:
|
||||
case ICK_Pointer_Conversion:
|
||||
case ICK_Pointer_Member:
|
||||
case ICK_Block_Pointer_Conversion:
|
||||
case ICK_Writeback_Conversion:
|
||||
case ICK_Floating_Promotion:
|
||||
case ICK_Complex_Promotion:
|
||||
case ICK_Complex_Conversion:
|
||||
case ICK_Floating_Conversion:
|
||||
case ICK_TransparentUnionConversion:
|
||||
llvm_unreachable("unexpected second conversion kind");
|
||||
llvm_unreachable("found a third conversion kind in Second");
|
||||
|
||||
case ICK_Num_Conversion_Kinds:
|
||||
break;
|
||||
@@ -4940,67 +4950,71 @@ static bool CheckConvertedConstantConversions(Sema &S,
|
||||
/// CheckConvertedConstantExpression - Check that the expression From is a
|
||||
/// converted constant expression of type T, perform the conversion and produce
|
||||
/// the converted expression, per C++11 [expr.const]p3.
|
||||
ExprResult Sema::CheckConvertedConstantExpression(Expr *From, QualType T,
|
||||
llvm::APSInt &Value,
|
||||
CCEKind CCE) {
|
||||
assert(LangOpts.CPlusPlus11 && "converted constant expression outside C++11");
|
||||
assert(T->isIntegralOrEnumerationType() && "unexpected converted const type");
|
||||
static ExprResult CheckConvertedConstantExpression(Sema &S, Expr *From,
|
||||
QualType T, APValue &Value,
|
||||
Sema::CCEKind CCE,
|
||||
bool RequireInt) {
|
||||
assert(S.getLangOpts().CPlusPlus11 &&
|
||||
"converted constant expression outside C++11");
|
||||
|
||||
if (checkPlaceholderForOverload(*this, From))
|
||||
if (checkPlaceholderForOverload(S, From))
|
||||
return ExprError();
|
||||
|
||||
// C++11 [expr.const]p3 with proposed wording fixes:
|
||||
// A converted constant expression of type T is a core constant expression,
|
||||
// implicitly converted to a prvalue of type T, where the converted
|
||||
// expression is a literal constant expression and the implicit conversion
|
||||
// sequence contains only user-defined conversions, lvalue-to-rvalue
|
||||
// conversions, integral promotions, and integral conversions other than
|
||||
// narrowing conversions.
|
||||
// C++1z [expr.const]p3:
|
||||
// A converted constant expression of type T is an expression,
|
||||
// implicitly converted to type T, where the converted
|
||||
// expression is a constant expression and the implicit conversion
|
||||
// sequence contains only [... list of conversions ...].
|
||||
ImplicitConversionSequence ICS =
|
||||
TryImplicitConversion(From, T,
|
||||
TryCopyInitialization(S, From, T,
|
||||
/*SuppressUserConversions=*/false,
|
||||
/*AllowExplicit=*/false,
|
||||
/*InOverloadResolution=*/false,
|
||||
/*CStyle=*/false,
|
||||
/*AllowObjcWritebackConversion=*/false);
|
||||
/*AllowObjcWritebackConversion=*/false,
|
||||
/*AllowExplicit=*/false);
|
||||
StandardConversionSequence *SCS = nullptr;
|
||||
switch (ICS.getKind()) {
|
||||
case ImplicitConversionSequence::StandardConversion:
|
||||
if (!CheckConvertedConstantConversions(*this, ICS.Standard))
|
||||
return Diag(From->getLocStart(),
|
||||
diag::err_typecheck_converted_constant_expression_disallowed)
|
||||
<< From->getType() << From->getSourceRange() << T;
|
||||
SCS = &ICS.Standard;
|
||||
break;
|
||||
case ImplicitConversionSequence::UserDefinedConversion:
|
||||
// We are converting from class type to an integral or enumeration type, so
|
||||
// the Before sequence must be trivial.
|
||||
if (!CheckConvertedConstantConversions(*this, ICS.UserDefined.After))
|
||||
return Diag(From->getLocStart(),
|
||||
diag::err_typecheck_converted_constant_expression_disallowed)
|
||||
<< From->getType() << From->getSourceRange() << T;
|
||||
// We are converting to a non-class type, so the Before sequence
|
||||
// must be trivial.
|
||||
SCS = &ICS.UserDefined.After;
|
||||
break;
|
||||
case ImplicitConversionSequence::AmbiguousConversion:
|
||||
case ImplicitConversionSequence::BadConversion:
|
||||
if (!DiagnoseMultipleUserDefinedConversion(From, T))
|
||||
return Diag(From->getLocStart(),
|
||||
diag::err_typecheck_converted_constant_expression)
|
||||
<< From->getType() << From->getSourceRange() << T;
|
||||
if (!S.DiagnoseMultipleUserDefinedConversion(From, T))
|
||||
return S.Diag(From->getLocStart(),
|
||||
diag::err_typecheck_converted_constant_expression)
|
||||
<< From->getType() << From->getSourceRange() << T;
|
||||
return ExprError();
|
||||
|
||||
case ImplicitConversionSequence::EllipsisConversion:
|
||||
llvm_unreachable("ellipsis conversion in converted constant expression");
|
||||
}
|
||||
|
||||
ExprResult Result = PerformImplicitConversion(From, T, ICS, AA_Converting);
|
||||
// Check that we would only use permitted conversions.
|
||||
if (!CheckConvertedConstantConversions(S, *SCS)) {
|
||||
return S.Diag(From->getLocStart(),
|
||||
diag::err_typecheck_converted_constant_expression_disallowed)
|
||||
<< From->getType() << From->getSourceRange() << T;
|
||||
}
|
||||
// [...] and where the reference binding (if any) binds directly.
|
||||
if (SCS->ReferenceBinding && !SCS->DirectBinding) {
|
||||
return S.Diag(From->getLocStart(),
|
||||
diag::err_typecheck_converted_constant_expression_indirect)
|
||||
<< From->getType() << From->getSourceRange() << T;
|
||||
}
|
||||
|
||||
ExprResult Result =
|
||||
S.PerformImplicitConversion(From, T, ICS, Sema::AA_Converting);
|
||||
if (Result.isInvalid())
|
||||
return Result;
|
||||
|
||||
// Check for a narrowing implicit conversion.
|
||||
APValue PreNarrowingValue;
|
||||
QualType PreNarrowingType;
|
||||
switch (SCS->getNarrowingKind(Context, Result.get(), PreNarrowingValue,
|
||||
switch (SCS->getNarrowingKind(S.Context, Result.get(), PreNarrowingValue,
|
||||
PreNarrowingType)) {
|
||||
case NK_Variable_Narrowing:
|
||||
// Implicit conversion to a narrower type, and the value is not a constant
|
||||
@@ -5009,13 +5023,13 @@ ExprResult Sema::CheckConvertedConstantExpression(Expr *From, QualType T,
|
||||
break;
|
||||
|
||||
case NK_Constant_Narrowing:
|
||||
Diag(From->getLocStart(), diag::ext_cce_narrowing)
|
||||
S.Diag(From->getLocStart(), diag::ext_cce_narrowing)
|
||||
<< CCE << /*Constant*/1
|
||||
<< PreNarrowingValue.getAsString(Context, PreNarrowingType) << T;
|
||||
<< PreNarrowingValue.getAsString(S.Context, PreNarrowingType) << T;
|
||||
break;
|
||||
|
||||
case NK_Type_Narrowing:
|
||||
Diag(From->getLocStart(), diag::ext_cce_narrowing)
|
||||
S.Diag(From->getLocStart(), diag::ext_cce_narrowing)
|
||||
<< CCE << /*Constant*/0 << From->getType() << T;
|
||||
break;
|
||||
}
|
||||
@@ -5025,12 +5039,15 @@ ExprResult Sema::CheckConvertedConstantExpression(Expr *From, QualType T,
|
||||
Expr::EvalResult Eval;
|
||||
Eval.Diag = &Notes;
|
||||
|
||||
if (!Result.get()->EvaluateAsRValue(Eval, Context) || !Eval.Val.isInt()) {
|
||||
if ((T->isReferenceType()
|
||||
? !Result.get()->EvaluateAsLValue(Eval, S.Context)
|
||||
: !Result.get()->EvaluateAsRValue(Eval, S.Context)) ||
|
||||
(RequireInt && !Eval.Val.isInt())) {
|
||||
// The expression can't be folded, so we can't keep it at this position in
|
||||
// the AST.
|
||||
Result = ExprError();
|
||||
} else {
|
||||
Value = Eval.Val.getInt();
|
||||
Value = Eval.Val;
|
||||
|
||||
if (Notes.empty()) {
|
||||
// It's a constant expression.
|
||||
@@ -5041,16 +5058,34 @@ ExprResult Sema::CheckConvertedConstantExpression(Expr *From, QualType T,
|
||||
// It's not a constant expression. Produce an appropriate diagnostic.
|
||||
if (Notes.size() == 1 &&
|
||||
Notes[0].second.getDiagID() == diag::note_invalid_subexpr_in_const_expr)
|
||||
Diag(Notes[0].first, diag::err_expr_not_cce) << CCE;
|
||||
S.Diag(Notes[0].first, diag::err_expr_not_cce) << CCE;
|
||||
else {
|
||||
Diag(From->getLocStart(), diag::err_expr_not_cce)
|
||||
S.Diag(From->getLocStart(), diag::err_expr_not_cce)
|
||||
<< CCE << From->getSourceRange();
|
||||
for (unsigned I = 0; I < Notes.size(); ++I)
|
||||
Diag(Notes[I].first, Notes[I].second);
|
||||
S.Diag(Notes[I].first, Notes[I].second);
|
||||
}
|
||||
return Result;
|
||||
return ExprError();
|
||||
}
|
||||
|
||||
ExprResult Sema::CheckConvertedConstantExpression(Expr *From, QualType T,
|
||||
APValue &Value, CCEKind CCE) {
|
||||
return ::CheckConvertedConstantExpression(*this, From, T, Value, CCE, false);
|
||||
}
|
||||
|
||||
ExprResult Sema::CheckConvertedConstantExpression(Expr *From, QualType T,
|
||||
llvm::APSInt &Value,
|
||||
CCEKind CCE) {
|
||||
assert(T->isIntegralOrEnumerationType() && "unexpected converted const type");
|
||||
|
||||
APValue V;
|
||||
auto R = ::CheckConvertedConstantExpression(*this, From, T, V, CCE, true);
|
||||
if (!R.isInvalid())
|
||||
Value = V.getInt();
|
||||
return R;
|
||||
}
|
||||
|
||||
|
||||
/// dropPointerConversions - If the given standard conversion sequence
|
||||
/// involves any pointer conversions, remove them. This may change
|
||||
/// the result type of the conversion sequence.
|
||||
|
||||
@@ -4759,13 +4759,111 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
|
||||
return Arg;
|
||||
}
|
||||
|
||||
QualType ParamType = InstantiatedParamType;
|
||||
if (getLangOpts().CPlusPlus1z) {
|
||||
// FIXME: We can do some limited checking for a value-dependent but not
|
||||
// type-dependent argument.
|
||||
if (Arg->isValueDependent()) {
|
||||
Converted = TemplateArgument(Arg);
|
||||
return Arg;
|
||||
}
|
||||
|
||||
// C++1z [temp.arg.nontype]p1:
|
||||
// A template-argument for a non-type template parameter shall be
|
||||
// a converted constant expression of the type of the template-parameter.
|
||||
APValue Value;
|
||||
ExprResult ArgResult = CheckConvertedConstantExpression(
|
||||
Arg, ParamType, Value, CCEK_TemplateArg);
|
||||
if (ArgResult.isInvalid())
|
||||
return ExprError();
|
||||
|
||||
// Convert the APValue to a TemplateArgument.
|
||||
switch (Value.getKind()) {
|
||||
case APValue::Uninitialized:
|
||||
assert(ParamType->isNullPtrType());
|
||||
Converted = TemplateArgument(ParamType, /*isNullPtr*/true);
|
||||
break;
|
||||
case APValue::Int:
|
||||
assert(ParamType->isIntegralOrEnumerationType());
|
||||
Converted = TemplateArgument(Context, Value.getInt(), ParamType);
|
||||
break;
|
||||
case APValue::MemberPointer: {
|
||||
assert(ParamType->isMemberPointerType());
|
||||
|
||||
// FIXME: We need TemplateArgument representation and mangling for these.
|
||||
if (!Value.getMemberPointerPath().empty()) {
|
||||
Diag(Arg->getLocStart(),
|
||||
diag::err_template_arg_member_ptr_base_derived_not_supported)
|
||||
<< Value.getMemberPointerDecl() << ParamType
|
||||
<< Arg->getSourceRange();
|
||||
return ExprError();
|
||||
}
|
||||
|
||||
auto *VD = const_cast<ValueDecl*>(Value.getMemberPointerDecl());
|
||||
Converted = VD ? TemplateArgument(VD, ParamType)
|
||||
: TemplateArgument(ParamType, /*isNullPtr*/true);
|
||||
break;
|
||||
}
|
||||
case APValue::LValue: {
|
||||
// For a non-type template-parameter of pointer or reference type,
|
||||
// the value of the constant expression shall not refer to
|
||||
assert(ParamType->isPointerType() || ParamType->isReferenceType());
|
||||
// -- a temporary object
|
||||
// -- a string literal
|
||||
// -- the result of a typeid expression, or
|
||||
// -- a predefind __func__ variable
|
||||
if (auto *E = Value.getLValueBase().dyn_cast<const Expr*>()) {
|
||||
if (isa<CXXUuidofExpr>(E)) {
|
||||
Converted = TemplateArgument(const_cast<Expr*>(E));
|
||||
break;
|
||||
}
|
||||
Diag(Arg->getLocStart(), diag::err_template_arg_not_decl_ref)
|
||||
<< Arg->getSourceRange();
|
||||
return ExprError();
|
||||
}
|
||||
auto *VD = const_cast<ValueDecl *>(
|
||||
Value.getLValueBase().dyn_cast<const ValueDecl *>());
|
||||
// -- a subobject
|
||||
if (Value.hasLValuePath() && Value.getLValuePath().size() == 1 &&
|
||||
VD && VD->getType()->isArrayType() &&
|
||||
Value.getLValuePath()[0].ArrayIndex == 0 &&
|
||||
!Value.isLValueOnePastTheEnd() && ParamType->isPointerType()) {
|
||||
// Per defect report (no number yet):
|
||||
// ... other than a pointer to the first element of a complete array
|
||||
// object.
|
||||
} else if (!Value.hasLValuePath() || Value.getLValuePath().size() ||
|
||||
Value.isLValueOnePastTheEnd()) {
|
||||
Diag(StartLoc, diag::err_non_type_template_arg_subobject)
|
||||
<< Value.getAsString(Context, ParamType);
|
||||
return ExprError();
|
||||
}
|
||||
assert((VD || ParamType->isPointerType()) &&
|
||||
"null reference should not be a constant expression");
|
||||
Converted = VD ? TemplateArgument(VD, ParamType)
|
||||
: TemplateArgument(ParamType, /*isNullPtr*/true);
|
||||
break;
|
||||
}
|
||||
case APValue::AddrLabelDiff:
|
||||
return Diag(StartLoc, diag::err_non_type_template_arg_addr_label_diff);
|
||||
case APValue::Float:
|
||||
case APValue::ComplexInt:
|
||||
case APValue::ComplexFloat:
|
||||
case APValue::Vector:
|
||||
case APValue::Array:
|
||||
case APValue::Struct:
|
||||
case APValue::Union:
|
||||
llvm_unreachable("invalid kind for template argument");
|
||||
}
|
||||
|
||||
return ArgResult.get();
|
||||
}
|
||||
|
||||
// C++ [temp.arg.nontype]p5:
|
||||
// The following conversions are performed on each expression used
|
||||
// as a non-type template-argument. If a non-type
|
||||
// template-argument cannot be converted to the type of the
|
||||
// corresponding template-parameter then the program is
|
||||
// ill-formed.
|
||||
QualType ParamType = InstantiatedParamType;
|
||||
if (ParamType->isIntegralOrEnumerationType()) {
|
||||
// C++11:
|
||||
// -- for a non-type template-parameter of integral or
|
||||
|
||||
@@ -521,17 +521,28 @@ namespace dr48 { // dr48: yes
|
||||
}
|
||||
|
||||
namespace dr49 { // dr49: yes
|
||||
template<int*> struct A {}; // expected-note {{here}}
|
||||
template<int*> struct A {}; // expected-note 0-2{{here}}
|
||||
int k;
|
||||
#if __has_feature(cxx_constexpr)
|
||||
constexpr
|
||||
#endif
|
||||
int *const p = &k;
|
||||
int *const p = &k; // expected-note 0-2{{here}}
|
||||
A<&k> a;
|
||||
A<p> b; // expected-error {{must have its address taken}}
|
||||
A<p> b;
|
||||
#if __cplusplus <= 201402L
|
||||
// expected-error@-2 {{must have its address taken}}
|
||||
#endif
|
||||
#if __cplusplus < 201103L
|
||||
// expected-error@-2 {{internal linkage}}
|
||||
// expected-note@-5 {{here}}
|
||||
// expected-error@-5 {{internal linkage}}
|
||||
#endif
|
||||
int *q = &k;
|
||||
A<q> c;
|
||||
#if __cplusplus < 201103L
|
||||
// expected-error@-2 {{must have its address taken}}
|
||||
#else
|
||||
// expected-error@-4 {{constant expression}}
|
||||
// expected-note@-5 {{read of non-constexpr}}
|
||||
// expected-note@-7 {{declared here}}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -995,6 +1006,10 @@ namespace dr92 { // dr92: yes
|
||||
g(q); // expected-error {{is not superset}}
|
||||
}
|
||||
|
||||
// Prior to C++17, this is OK because the exception specification is not
|
||||
// considered in this context. In C++17, we *do* perform an implicit
|
||||
// conversion (which performs initialization), but we convert to the type of
|
||||
// the template parameter, which does not include the exception specification.
|
||||
template<void() throw()> struct X {};
|
||||
X<&f> xp; // ok
|
||||
}
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
// RUN: %clang_cc1 -std=c++1z -triple x86_64-unknown-unknown %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
|
||||
|
||||
namespace dr100 { // dr100: yes
|
||||
template<const char *> struct A {}; // expected-note {{declared here}}
|
||||
template<const char (&)[4]> struct B {}; // expected-note {{declared here}}
|
||||
template<const char *> struct A {}; // expected-note 0-1{{declared here}}
|
||||
template<const char (&)[4]> struct B {}; // expected-note 0-1{{declared here}}
|
||||
A<"foo"> a; // expected-error {{does not refer to any declaration}}
|
||||
B<"bar"> b; // expected-error {{does not refer to any declaration}}
|
||||
}
|
||||
|
||||
@@ -991,12 +991,11 @@ namespace dr289 { // dr289: yes
|
||||
namespace dr294 { // dr294: no
|
||||
void f() throw(int);
|
||||
int main() {
|
||||
// FIXME: we reject this for the wrong reason, because we don't implement
|
||||
// dr87 yet.
|
||||
(void)static_cast<void (*)() throw()>(f); // expected-error {{not superset}}
|
||||
void (*p)() throw() = f; // expected-error {{not superset}}
|
||||
|
||||
(void)static_cast<void (*)() throw()>(f); // FIXME: ill-formed
|
||||
(void)static_cast<void (*)() throw(int)>(f); // FIXME: ill-formed
|
||||
|
||||
void (*p)() throw() = f; // expected-error {{not superset}}
|
||||
void (*q)() throw(int) = f;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -705,7 +705,7 @@ namespace dr354 { // dr354: yes c++11
|
||||
// FIXME: Should we allow this in C++98 too?
|
||||
struct S {};
|
||||
|
||||
template<int*> struct ptr {}; // expected-note +{{here}}
|
||||
template<int*> struct ptr {}; // expected-note 0-4{{here}}
|
||||
ptr<0> p0;
|
||||
ptr<(int*)0> p1;
|
||||
ptr<(float*)0> p2;
|
||||
@@ -715,11 +715,16 @@ namespace dr354 { // dr354: yes c++11
|
||||
// expected-error@-5 {{does not refer to any decl}}
|
||||
// expected-error@-5 {{does not refer to any decl}}
|
||||
// expected-error@-5 {{does not refer to any decl}}
|
||||
#else
|
||||
#elif __cplusplus <= 201402L
|
||||
// expected-error@-10 {{must be cast}}
|
||||
// ok
|
||||
// expected-error@-10 {{does not match}}
|
||||
// expected-error@-10 {{does not match}}
|
||||
#else
|
||||
// expected-error@-15 {{conversion from 'int' to 'int *' is not allowed}}
|
||||
// ok
|
||||
// expected-error@-15 {{'float *' is not implicitly convertible to 'int *'}}
|
||||
// expected-error@-15 {{'int dr354::S::*' is not implicitly convertible to 'int *'}}
|
||||
#endif
|
||||
|
||||
template<int*> int both();
|
||||
@@ -732,7 +737,7 @@ namespace dr354 { // dr354: yes c++11
|
||||
// expected-note@-6 {{candidate}}
|
||||
#endif
|
||||
|
||||
template<int S::*> struct ptr_mem {}; // expected-note +{{here}}
|
||||
template<int S::*> struct ptr_mem {}; // expected-note 0-4{{here}}
|
||||
ptr_mem<0> m0;
|
||||
ptr_mem<(int S::*)0> m1;
|
||||
ptr_mem<(float S::*)0> m2;
|
||||
@@ -742,11 +747,16 @@ namespace dr354 { // dr354: yes c++11
|
||||
// expected-error@-5 {{is not a pointer to member constant}}
|
||||
// expected-error@-5 {{cannot be converted}}
|
||||
// expected-error@-5 {{cannot be converted}}
|
||||
#else
|
||||
#elif __cplusplus <= 201402L
|
||||
// expected-error@-10 {{must be cast}}
|
||||
// ok
|
||||
// expected-error@-10 {{does not match}}
|
||||
// expected-error@-10 {{does not match}}
|
||||
#else
|
||||
// expected-error@-15 {{conversion from 'int' to 'int dr354::S::*' is not allowed}}
|
||||
// ok
|
||||
// expected-error@-15 {{'float dr354::S::*' is not implicitly convertible to 'int dr354::S::*'}}
|
||||
// expected-error@-15 {{'int *' is not implicitly convertible to 'int dr354::S::*'}}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -131,14 +131,14 @@ namespace IncompleteClassTypeAddr {
|
||||
namespace UndefinedBehavior {
|
||||
void f(int n) {
|
||||
switch (n) {
|
||||
case (int)4.4e9: // expected-error {{constant expression}} expected-note {{value 4.4E+9 is outside the range of representable values of type 'int'}} expected-note {{previous case defined here}}
|
||||
case (int)4.4e9: // expected-error {{constant expression}} expected-note {{value 4.4E+9 is outside the range of representable values of type 'int'}}
|
||||
case (int)0x80000000u: // ok
|
||||
case (int)10000000000ll: // expected-note {{here}}
|
||||
case (unsigned int)10000000000ll: // expected-error {{duplicate case value}}
|
||||
case (int)(unsigned)(long long)4.4e9: // ok
|
||||
case (int)(float)1e300: // expected-error {{constant expression}} expected-note {{value 1.0E+300 is outside the range of representable values of type 'float'}} expected-error {{duplicate case value '2147483647'}} expected-note {{previous case defined here}}
|
||||
case (int)(float)1e300: // expected-error {{constant expression}} expected-note {{value 1.0E+300 is outside the range of representable values of type 'float'}}
|
||||
case (int)((float)1e37 / 1e30): // ok
|
||||
case (int)(__fp16)65536: // expected-error {{constant expression}} expected-note {{value 65536 is outside the range of representable values of type '__fp16'}} expected-error {{duplicate case value '2147483647'}}
|
||||
case (int)(__fp16)65536: // expected-error {{constant expression}} expected-note {{value 65536 is outside the range of representable values of type '__fp16'}}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
112
clang/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp
Normal file
112
clang/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp
Normal file
@@ -0,0 +1,112 @@
|
||||
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++1z %s
|
||||
|
||||
template<typename T, T val> struct A {};
|
||||
|
||||
template<typename T, typename U> constexpr bool is_same = false; // expected-note +{{here}}
|
||||
template<typename T> constexpr bool is_same<T, T> = true;
|
||||
|
||||
namespace String {
|
||||
A<const char*, "test"> a; // expected-error {{does not refer to any declaration}}
|
||||
A<const char (&)[5], "test"> b; // expected-error {{does not refer to any declaration}}
|
||||
}
|
||||
|
||||
namespace Array {
|
||||
char arr[3];
|
||||
char x;
|
||||
A<const char*, arr> a;
|
||||
A<const char(&)[3], arr> b;
|
||||
A<const char*, &arr[0]> c;
|
||||
A<const char*, &arr[1]> d; // expected-error {{refers to subobject '&arr[1]'}}
|
||||
A<const char*, (&arr)[0]> e;
|
||||
A<const char*, &x> f;
|
||||
A<const char*, &(&x)[0]> g;
|
||||
A<const char*, &(&x)[1]> h; // expected-error {{refers to subobject '&x + 1'}}
|
||||
A<const char*, 0> i; // expected-error {{not allowed in a converted constant}}
|
||||
A<const char*, nullptr> j;
|
||||
}
|
||||
|
||||
namespace Function {
|
||||
void f();
|
||||
void g() noexcept;
|
||||
void h();
|
||||
void h(int);
|
||||
template<typename...T> void i(T...);
|
||||
typedef A<void (*)(), f> a;
|
||||
typedef A<void (*)(), &f> a;
|
||||
typedef A<void (*)(), g> b;
|
||||
typedef A<void (*)(), &g> b;
|
||||
typedef A<void (*)(), h> c;
|
||||
typedef A<void (*)(), &h> c;
|
||||
typedef A<void (*)(), i> d;
|
||||
typedef A<void (*)(), &i> d;
|
||||
typedef A<void (*)(), i<>> d;
|
||||
typedef A<void (*)(), i<int>> e; // expected-error {{is not implicitly convertible}}
|
||||
|
||||
typedef A<void (*)(), 0> x; // expected-error {{not allowed in a converted constant}}
|
||||
typedef A<void (*)(), nullptr> y;
|
||||
}
|
||||
|
||||
void Func() {
|
||||
A<const char*, __func__> a; // expected-error {{does not refer to any declaration}}
|
||||
}
|
||||
|
||||
namespace LabelAddrDiff {
|
||||
void f() {
|
||||
a: b: A<int, __builtin_constant_p(true) ? (long)&&b - (long)&&a : 0> s; // expected-error {{label address difference}}
|
||||
};
|
||||
}
|
||||
|
||||
namespace Temp {
|
||||
struct S { int n; };
|
||||
constexpr S &addr(S &&s) { return s; }
|
||||
A<S &, addr({})> a; // expected-error {{constant}} expected-note 2{{temporary}}
|
||||
A<S *, &addr({})> b; // expected-error {{constant}} expected-note 2{{temporary}}
|
||||
A<int &, addr({}).n> c; // expected-error {{constant}} expected-note 2{{temporary}}
|
||||
A<int *, &addr({}).n> d; // expected-error {{constant}} expected-note 2{{temporary}}
|
||||
}
|
||||
|
||||
namespace std { struct type_info; }
|
||||
|
||||
namespace RTTI {
|
||||
A<const std::type_info&, typeid(int)> a; // expected-error {{does not refer to any declaration}}
|
||||
A<const std::type_info*, &typeid(int)> b; // expected-error {{does not refer to any declaration}}
|
||||
}
|
||||
|
||||
namespace PtrMem {
|
||||
struct B { int b; };
|
||||
struct C : B {};
|
||||
struct D : B {};
|
||||
struct E : C, D { int e; };
|
||||
|
||||
constexpr int B::*b = &B::b;
|
||||
constexpr int C::*cb = b;
|
||||
constexpr int D::*db = b;
|
||||
constexpr int E::*ecb = cb; // expected-note +{{here}}
|
||||
constexpr int E::*edb = db; // expected-note +{{here}}
|
||||
|
||||
constexpr int E::*e = &E::e;
|
||||
constexpr int D::*de = (int D::*)e;
|
||||
constexpr int C::*ce = (int C::*)e;
|
||||
constexpr int B::*bde = (int B::*)de; // expected-note +{{here}}
|
||||
constexpr int B::*bce = (int B::*)ce; // expected-note +{{here}}
|
||||
|
||||
// FIXME: This should all be accepted, but we don't yet have a representation
|
||||
// nor mangling for this form of template argument.
|
||||
using Ab = A<int B::*, b>;
|
||||
using Ab = A<int B::*, &B::b>;
|
||||
using Abce = A<int B::*, bce>; // expected-error {{not supported}}
|
||||
using Abde = A<int B::*, bde>; // expected-error {{not supported}}
|
||||
static_assert(!is_same<Ab, Abce>, ""); // expected-error {{undeclared}} expected-error {{must be a type}}
|
||||
static_assert(!is_same<Ab, Abde>, ""); // expected-error {{undeclared}} expected-error {{must be a type}}
|
||||
static_assert(!is_same<Abce, Abde>, ""); // expected-error 2{{undeclared}} expected-error {{must be a type}}
|
||||
static_assert(is_same<Abce, A<int B::*, (int B::*)(int C::*)&E::e>, ""); // expected-error {{undeclared}} expected-error {{not supported}}
|
||||
|
||||
using Ae = A<int E::*, e>;
|
||||
using Ae = A<int E::*, &E::e>;
|
||||
using Aecb = A<int E::*, ecb>; // expected-error {{not supported}}
|
||||
using Aedb = A<int E::*, edb>; // expected-error {{not supported}}
|
||||
static_assert(!is_same<Ae, Aecb>, ""); // expected-error {{undeclared}} expected-error {{must be a type}}
|
||||
static_assert(!is_same<Ae, Aedb>, ""); // expected-error {{undeclared}} expected-error {{must be a type}}
|
||||
static_assert(!is_same<Aecb, Aedb>, ""); // expected-error 2{{undeclared}} expected-error {{must be a type}}
|
||||
static_assert(is_same<Aecb, A<int E::*, (int E::*)(int C::*)&B::b>, ""); // expected-error {{undeclared}} expected-error {{not supported}}
|
||||
}
|
||||
@@ -533,7 +533,7 @@ as the draft C++1z standard evolves.</p>
|
||||
<!-- Rapperswil papers -->
|
||||
<tr>
|
||||
<td>Disabling trigraph expansion by default</td>
|
||||
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3981.html">N3981</a></td>
|
||||
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4086.html">N4086</a></td>
|
||||
<td class="full" align="center">Clang 3.5</td>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -546,6 +546,11 @@ as the draft C++1z standard evolves.</p>
|
||||
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4051.html">N4051</a></td>
|
||||
<td class="full" align="center">Clang 3.5</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>New <tt>auto</tt> rules for direct-list-initialization
|
||||
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3922.html">N3922</a></td>
|
||||
<td class="no" align="center">No</td>
|
||||
</tr>
|
||||
<!-- Urbana papers -->
|
||||
<tr>
|
||||
<td>Fold expressions</td>
|
||||
@@ -567,6 +572,11 @@ as the draft C++1z standard evolves.</p>
|
||||
<td><!--<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4266.html">-->N4266<!--</a>--></td>
|
||||
<td class="svn" align="center">SVN</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Allow constant evaluation for all non-type template arguments</td>
|
||||
<td><!--<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4268.html">-->N4268<!--</a>--></td>
|
||||
<td class="svn" align="center">SVN</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<h2 id="ts">Technical specifications and standing documents</h2>
|
||||
|
||||
Reference in New Issue
Block a user