From 410cc893745ee511d51009b712bb987a8a980c24 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Wed, 26 Nov 2014 03:26:53 +0000 Subject: [PATCH] [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 --- clang/include/clang/Basic/DiagnosticSemaKinds.td | 10 ++ clang/include/clang/Sema/Sema.h | 2 + clang/lib/Sema/SemaExprCXX.cpp | 27 +++- clang/lib/Sema/SemaOverload.cpp | 159 +++++++++++++-------- clang/lib/Sema/SemaTemplate.cpp | 100 ++++++++++++- clang/test/CXX/drs/dr0xx.cpp | 25 +++- clang/test/CXX/drs/dr1xx.cpp | 4 +- clang/test/CXX/drs/dr2xx.cpp | 9 +- clang/test/CXX/drs/dr3xx.cpp | 18 ++- clang/test/CXX/expr/expr.const/p2-0x.cpp | 6 +- clang/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp | 112 +++++++++++++++ clang/www/cxx_status.html | 12 +- 12 files changed, 397 insertions(+), 87 deletions(-) create mode 100644 clang/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 9639b3c..25441cd 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -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< diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 92a4a47..06292d25 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -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. diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index c71a4e9..0d11e42 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -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; diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 5e02647..d33f126 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -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"); - - if (checkPlaceholderForOverload(*this, From)) +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(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. diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 08ab0a0..3c17bd3 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -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(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()) { + if (isa(E)) { + Converted = TemplateArgument(const_cast(E)); + break; + } + Diag(Arg->getLocStart(), diag::err_template_arg_not_decl_ref) + << Arg->getSourceRange(); + return ExprError(); + } + auto *VD = const_cast( + Value.getLValueBase().dyn_cast()); + // -- 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 diff --git a/clang/test/CXX/drs/dr0xx.cpp b/clang/test/CXX/drs/dr0xx.cpp index 011b420..5b34cc3 100644 --- a/clang/test/CXX/drs/dr0xx.cpp +++ b/clang/test/CXX/drs/dr0xx.cpp @@ -521,17 +521,28 @@ namespace dr48 { // dr48: yes } namespace dr49 { // dr49: yes - template struct A {}; // expected-note {{here}} + template 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

b; // expected-error {{must have its address taken}} + A

b; +#if __cplusplus <= 201402L + // expected-error@-2 {{must have its address taken}} +#endif +#if __cplusplus < 201103L + // expected-error@-5 {{internal linkage}} +#endif + int *q = &k; + A c; #if __cplusplus < 201103L - // expected-error@-2 {{internal linkage}} - // expected-note@-5 {{here}} + // 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 struct X {}; X<&f> xp; // ok } diff --git a/clang/test/CXX/drs/dr1xx.cpp b/clang/test/CXX/drs/dr1xx.cpp index 89d0d84..cc6c5af 100644 --- a/clang/test/CXX/drs/dr1xx.cpp +++ b/clang/test/CXX/drs/dr1xx.cpp @@ -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 struct A {}; // expected-note {{declared here}} - template struct B {}; // expected-note {{declared here}} + template struct A {}; // expected-note 0-1{{declared here}} + template 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}} } diff --git a/clang/test/CXX/drs/dr2xx.cpp b/clang/test/CXX/drs/dr2xx.cpp index e4e7554..bb1f13a 100644 --- a/clang/test/CXX/drs/dr2xx.cpp +++ b/clang/test/CXX/drs/dr2xx.cpp @@ -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(f); // expected-error {{not superset}} - void (*p)() throw() = f; // expected-error {{not superset}} - + (void)static_cast(f); // FIXME: ill-formed (void)static_cast(f); // FIXME: ill-formed + + void (*p)() throw() = f; // expected-error {{not superset}} + void (*q)() throw(int) = f; } } diff --git a/clang/test/CXX/drs/dr3xx.cpp b/clang/test/CXX/drs/dr3xx.cpp index 59deaca..6cf3a29 100644 --- a/clang/test/CXX/drs/dr3xx.cpp +++ b/clang/test/CXX/drs/dr3xx.cpp @@ -705,7 +705,7 @@ namespace dr354 { // dr354: yes c++11 // FIXME: Should we allow this in C++98 too? struct S {}; - template struct ptr {}; // expected-note +{{here}} + template 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 both(); @@ -732,7 +737,7 @@ namespace dr354 { // dr354: yes c++11 // expected-note@-6 {{candidate}} #endif - template struct ptr_mem {}; // expected-note +{{here}} + template 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 } diff --git a/clang/test/CXX/expr/expr.const/p2-0x.cpp b/clang/test/CXX/expr/expr.const/p2-0x.cpp index 249e552..d027c7a 100644 --- a/clang/test/CXX/expr/expr.const/p2-0x.cpp +++ b/clang/test/CXX/expr/expr.const/p2-0x.cpp @@ -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; } } diff --git a/clang/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp b/clang/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp new file mode 100644 index 0000000..f49ee034 --- /dev/null +++ b/clang/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp @@ -0,0 +1,112 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -std=c++1z %s + +template struct A {}; + +template constexpr bool is_same = false; // expected-note +{{here}} +template constexpr bool is_same = true; + +namespace String { + A a; // expected-error {{does not refer to any declaration}} + A b; // expected-error {{does not refer to any declaration}} +} + +namespace Array { + char arr[3]; + char x; + A a; + A b; + A c; + A d; // expected-error {{refers to subobject '&arr[1]'}} + A e; + A f; + A g; + A h; // expected-error {{refers to subobject '&x + 1'}} + A i; // expected-error {{not allowed in a converted constant}} + A j; +} + +namespace Function { + void f(); + void g() noexcept; + void h(); + void h(int); + template void i(T...); + typedef A a; + typedef A a; + typedef A b; + typedef A b; + typedef A c; + typedef A c; + typedef A d; + typedef A d; + typedef A> d; + typedef A> e; // expected-error {{is not implicitly convertible}} + + typedef A x; // expected-error {{not allowed in a converted constant}} + typedef A y; +} + +void Func() { + A a; // expected-error {{does not refer to any declaration}} +} + +namespace LabelAddrDiff { + void f() { + a: b: A s; // expected-error {{label address difference}} + }; +} + +namespace Temp { + struct S { int n; }; + constexpr S &addr(S &&s) { return s; } + A a; // expected-error {{constant}} expected-note 2{{temporary}} + A b; // expected-error {{constant}} expected-note 2{{temporary}} + A c; // expected-error {{constant}} expected-note 2{{temporary}} + A d; // expected-error {{constant}} expected-note 2{{temporary}} +} + +namespace std { struct type_info; } + +namespace RTTI { + A a; // expected-error {{does not refer to any declaration}} + A 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; + using Ab = A; + using Abce = A; // expected-error {{not supported}} + using Abde = A; // expected-error {{not supported}} + static_assert(!is_same, ""); // expected-error {{undeclared}} expected-error {{must be a type}} + static_assert(!is_same, ""); // expected-error {{undeclared}} expected-error {{must be a type}} + static_assert(!is_same, ""); // expected-error 2{{undeclared}} expected-error {{must be a type}} + static_assert(is_same, ""); // expected-error {{undeclared}} expected-error {{not supported}} + + using Ae = A; + using Ae = A; + using Aecb = A; // expected-error {{not supported}} + using Aedb = A; // expected-error {{not supported}} + static_assert(!is_same, ""); // expected-error {{undeclared}} expected-error {{must be a type}} + static_assert(!is_same, ""); // expected-error {{undeclared}} expected-error {{must be a type}} + static_assert(!is_same, ""); // expected-error 2{{undeclared}} expected-error {{must be a type}} + static_assert(is_same, ""); // expected-error {{undeclared}} expected-error {{not supported}} +} diff --git a/clang/www/cxx_status.html b/clang/www/cxx_status.html index cdb05a1..7b6fac0 100644 --- a/clang/www/cxx_status.html +++ b/clang/www/cxx_status.html @@ -533,7 +533,7 @@ as the draft C++1z standard evolves.

Disabling trigraph expansion by default - N3981 + N4086 Clang 3.5 @@ -546,6 +546,11 @@ as the draft C++1z standard evolves.

N4051 Clang 3.5 + + New auto rules for direct-list-initialization + N3922 + No + Fold expressions @@ -567,6 +572,11 @@ as the draft C++1z standard evolves.

N4266 SVN + + Allow constant evaluation for all non-type template arguments + N4268 + SVN +

Technical specifications and standing documents

-- 2.7.4