diff options
| -rw-r--r-- | clang/lib/Sema/SemaTemplate.cpp | 149 | ||||
| -rw-r--r-- | clang/test/SemaCXX/exceptions-seh.cpp | 7 | ||||
| -rw-r--r-- | clang/test/SemaCXX/warn-bool-conversion.cpp | 24 | ||||
| -rw-r--r-- | clang/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp | 32 | 
4 files changed, 118 insertions, 94 deletions
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index e800f7fe742..7dd1e9075c1 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -6968,100 +6968,73 @@ Sema::BuildExpressionFromDeclTemplateArgument(const TemplateArgument &Arg,    ValueDecl *VD = Arg.getAsDecl(); -  if (VD->getDeclContext()->isRecord() && -      (isa<CXXMethodDecl>(VD) || isa<FieldDecl>(VD) || -       isa<IndirectFieldDecl>(VD))) { -    // If the value is a class member, we might have a pointer-to-member. -    // Determine whether the non-type template template parameter is of -    // pointer-to-member type. If so, we need to build an appropriate -    // expression for a pointer-to-member, since a "normal" DeclRefExpr -    // would refer to the member itself. -    if (ParamType->isMemberPointerType()) { -      QualType ClassType -        = Context.getTypeDeclType(cast<RecordDecl>(VD->getDeclContext())); -      NestedNameSpecifier *Qualifier -        = NestedNameSpecifier::Create(Context, nullptr, false, -                                      ClassType.getTypePtr()); -      CXXScopeSpec SS; -      SS.MakeTrivial(Context, Qualifier, Loc); - -      // The actual value-ness of this is unimportant, but for -      // internal consistency's sake, references to instance methods -      // are r-values. -      ExprValueKind VK = VK_LValue; -      if (isa<CXXMethodDecl>(VD) && cast<CXXMethodDecl>(VD)->isInstance()) -        VK = VK_RValue; - -      ExprResult RefExpr = BuildDeclRefExpr(VD, -                                            VD->getType().getNonReferenceType(), -                                            VK, -                                            Loc, -                                            &SS); -      if (RefExpr.isInvalid()) -        return ExprError(); - -      RefExpr = CreateBuiltinUnaryOp(Loc, UO_AddrOf, RefExpr.get()); - -      // We might need to perform a trailing qualification conversion, since -      // the element type on the parameter could be more qualified than the -      // element type in the expression we constructed, and likewise for a -      // function conversion. -      bool ObjCLifetimeConversion; -      QualType Ignored; -      if (IsFunctionConversion(RefExpr.get()->getType(), ParamType, Ignored) || -          IsQualificationConversion(RefExpr.get()->getType(), -                                    ParamType.getUnqualifiedType(), false, -                                    ObjCLifetimeConversion)) -        RefExpr = ImpCastExprToType(RefExpr.get(), -                                    ParamType.getUnqualifiedType(), CK_NoOp); - -      // FIXME: We need to perform derived-to-base or base-to-derived -      // pointer-to-member conversions here too. -      assert(!RefExpr.isInvalid() && -             Context.hasSameType(RefExpr.get()->getType(), -                                 ParamType.getUnqualifiedType())); -      return RefExpr; -    } -  } - -  QualType T = VD->getType().getNonReferenceType(); +  CXXScopeSpec SS; +  if (ParamType->isMemberPointerType()) { +    // If this is a pointer to member, we need to use a qualified name to +    // form a suitable pointer-to-member constant. +    assert(VD->getDeclContext()->isRecord() && +           (isa<CXXMethodDecl>(VD) || isa<FieldDecl>(VD) || +            isa<IndirectFieldDecl>(VD))); +    QualType ClassType +      = Context.getTypeDeclType(cast<RecordDecl>(VD->getDeclContext())); +    NestedNameSpecifier *Qualifier +      = NestedNameSpecifier::Create(Context, nullptr, false, +                                    ClassType.getTypePtr()); +    SS.MakeTrivial(Context, Qualifier, Loc); +  } + +  ExprResult RefExpr = BuildDeclarationNameExpr( +      SS, DeclarationNameInfo(VD->getDeclName(), Loc), VD); +  if (RefExpr.isInvalid()) +    return ExprError(); -  if (ParamType->isPointerType()) { -    // When the non-type template parameter is a pointer, take the -    // address of the declaration. -    ExprResult RefExpr = BuildDeclRefExpr(VD, T, VK_LValue, Loc); +  // For a pointer, the argument declaration is the pointee. Take its address. +  QualType ElemT(RefExpr.get()->getType()->getArrayElementTypeNoTypeQual(), 0); +  if (ParamType->isPointerType() && !ElemT.isNull() && +      Context.hasSimilarType(ElemT, ParamType->getPointeeType())) { +    // Decay an array argument if we want a pointer to its first element. +    RefExpr = DefaultFunctionArrayConversion(RefExpr.get());      if (RefExpr.isInvalid())        return ExprError(); - -    if (!Context.hasSameUnqualifiedType(ParamType->getPointeeType(), T) && -        (T->isFunctionType() || T->isArrayType())) { -      // Decay functions and arrays unless we're forming a pointer to array. -      RefExpr = DefaultFunctionArrayConversion(RefExpr.get()); -      if (RefExpr.isInvalid()) -        return ExprError(); - -      return RefExpr; +  } else if (ParamType->isPointerType() || ParamType->isMemberPointerType()) { +    // For any other pointer, take the address (or form a pointer-to-member). +    RefExpr = CreateBuiltinUnaryOp(Loc, UO_AddrOf, RefExpr.get()); +    if (RefExpr.isInvalid()) +      return ExprError(); +  } else { +    assert(ParamType->isReferenceType() && +           "unexpected type for decl template argument"); +  } + +  // At this point we should have the right value category. +  assert(ParamType->isReferenceType() == RefExpr.get()->isLValue() && +         "value kind mismatch for non-type template argument"); + +  // The type of the template parameter can differ from the type of the +  // argument in various ways; convert it now if necessary. +  QualType DestExprType = ParamType.getNonLValueExprType(Context); +  if (!Context.hasSameType(RefExpr.get()->getType(), DestExprType)) { +    CastKind CK; +    QualType Ignored; +    if (Context.hasSimilarType(RefExpr.get()->getType(), DestExprType) || +        IsFunctionConversion(RefExpr.get()->getType(), DestExprType, Ignored)) { +      CK = CK_NoOp; +    } else if (ParamType->isVoidPointerType() && +               RefExpr.get()->getType()->isPointerType()) { +      CK = CK_BitCast; +    } else { +      // FIXME: Pointers to members can need conversion derived-to-base or +      // base-to-derived conversions. We currently don't retain enough +      // information to convert properly (we need to track a cast path or +      // subobject number in the template argument). +      llvm_unreachable( +          "unexpected conversion required for non-type template argument");      } - -    // Take the address of everything else -    return CreateBuiltinUnaryOp(Loc, UO_AddrOf, RefExpr.get()); -  } - -  ExprValueKind VK = VK_RValue; - -  // If the non-type template parameter has reference type, qualify the -  // resulting declaration reference with the extra qualifiers on the -  // type that the reference refers to. -  if (const ReferenceType *TargetRef = ParamType->getAs<ReferenceType>()) { -    VK = VK_LValue; -    T = Context.getQualifiedType(T, -                              TargetRef->getPointeeType().getQualifiers()); -  } else if (isa<FunctionDecl>(VD)) { -    // References to functions are always lvalues. -    VK = VK_LValue; +    RefExpr = ImpCastExprToType(RefExpr.get(), DestExprType, CK, +                                RefExpr.get()->getValueKind());    } -  return BuildDeclRefExpr(VD, T, VK, Loc); +  return RefExpr;  }  /// Construct a new expression that refers to the given diff --git a/clang/test/SemaCXX/exceptions-seh.cpp b/clang/test/SemaCXX/exceptions-seh.cpp index 1d8cc4917e9..02bb786160d 100644 --- a/clang/test/SemaCXX/exceptions-seh.cpp +++ b/clang/test/SemaCXX/exceptions-seh.cpp @@ -39,14 +39,13 @@ void instantiate_bad_scope_tmpl() {  }  #if __cplusplus < 201103L -// FIXME: Diagnose this case. For now we produce undef in codegen.  template <typename T, T FN()>  T func_template() { -  return FN(); +  return FN(); // expected-error 2{{builtin functions must be directly called}}  }  void inject_builtins() { -  func_template<void *, __exception_info>(); -  func_template<unsigned long, __exception_code>(); +  func_template<void *, __exception_info>(); // expected-note {{instantiation of}} +  func_template<unsigned long, __exception_code>(); // expected-note {{instantiation of}}  }  #endif diff --git a/clang/test/SemaCXX/warn-bool-conversion.cpp b/clang/test/SemaCXX/warn-bool-conversion.cpp index ab563aa6898..6eca171f254 100644 --- a/clang/test/SemaCXX/warn-bool-conversion.cpp +++ b/clang/test/SemaCXX/warn-bool-conversion.cpp @@ -1,6 +1,6 @@ -// RUN: %clang_cc1 -fsyntax-only -verify %s +// RUN: %clang_cc1 -fsyntax-only -verify=expected,expected-cxx11 %s  // RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s -// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s +// RUN: %clang_cc1 -fsyntax-only -verify=expected,expected-cxx11 -std=c++11 %s  namespace BooleanFalse {  int* j = false; @@ -192,3 +192,23 @@ namespace macros {      // expected-warning@-1{{address of 'x' will always evaluate to 'true'}}    }  } + +namespace Template { +  // FIXME: These cases should not warn. +  template<int *p> void f() { if (p) {} } // expected-warning 2{{will always evaluate to 'true'}} expected-cxx11-warning {{implicit conversion of nullptr}} +  template<int (*p)[3]> void g() { if (p) {} } // expected-warning 2{{will always evaluate to 'true'}} expected-cxx11-warning {{implicit conversion of nullptr}} +  template<int (*p)()> void h() { if (p) {} } + +  int a, b[3], c[3][3], d(); +  template void f<&a>(); // expected-note {{instantiation of}} +  template void f<b>(); // expected-note {{instantiation of}} +#if __cplusplus >= 201103L +  template void f<(int*)nullptr>(); // expected-note {{instantiation of}} +#endif +  template void g<&b>(); // expected-note {{instantiation of}} +  template void g<c>(); // expected-note {{instantiation of}} +#if __cplusplus >= 201103L +  template void g<(int(*)[3])nullptr>(); // expected-note {{instantiation of}} +#endif +  template void h<d>(); +} diff --git a/clang/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp b/clang/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp index 7a58dd5dcae..7232598215a 100644 --- a/clang/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp +++ b/clang/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp @@ -394,6 +394,21 @@ namespace PR42362 {    Z<f, f, f>::Q q;  } +namespace QualConv { +  int *X; +  template<const int *const *P> void f() { +    using T = decltype(P); +    using T = const int* const*; +  } +  template void f<&X>(); + +  template<const int *const &R> void g() { +    using T = decltype(R); +    using T = const int *const &; +  } +  template void g<(const int *const&)X>(); +} +  namespace FunctionConversion {    struct a { void c(char *) noexcept; };    template<void (a::*f)(char*)> void g() { @@ -401,4 +416,21 @@ namespace FunctionConversion {      using T = void (a::*)(char*); // (not 'noexcept')    }    template void g<&a::c>(); + +  void c() noexcept; +  template<void (*p)()> void h() { +    using T = decltype(p); +    using T = void (*)(); // (not 'noexcept') +  } +  template void h<&c>(); +} + +namespace VoidPtr { +  // Note, this is an extension in C++17 but valid in C++20. +  template<void *P> void f() { +    using T = decltype(P); +    using T = void*; +  } +  int n; +  template void f<(void*)&n>();  }  | 

