[clang] 93cc9dd - Revert "Properly convert all declaration non-type template arguments when"

David L. Jones via cfe-commits cfe-commits at lists.llvm.org
Wed Dec 4 22:31:52 PST 2019


Author: David L. Jones
Date: 2019-12-04T22:12:15-08:00
New Revision: 93cc9dddd82f9e971f382ade6acf6634c5914966

URL: https://github.com/llvm/llvm-project/commit/93cc9dddd82f9e971f382ade6acf6634c5914966
DIFF: https://github.com/llvm/llvm-project/commit/93cc9dddd82f9e971f382ade6acf6634c5914966.diff

LOG: Revert "Properly convert all declaration non-type template arguments when"

This reverts commit 11d10527852b4d3ed738aa90d8bec0f398160593.

This change is problematic with function pointer template parameters. For
example, building libcxxabi with futexes (-D_LIBCXXABI_USE_FUTEX) produces this
diagnostic:

    In file included from .../llvm-project/libcxxabi/src/cxa_guard.cpp:15:
    .../llvm-project/libcxxabi/src/cxa_guard_impl.h:416:54: error: address of function 'PlatformThreadID' will always evaluate to 'true' [-Werror,-Wpointer-bool-conversion]
        has_thread_id_support(this->thread_id_address && GetThreadIDArg),
                                                      ~~ ^~~~~~~~~~~~~~
    .../llvm-project/libcxxabi/src/cxa_guard.cpp:38:26: note: in instantiation of member function '__cxxabiv1::(anonymous namespace)::InitByteFutex<&__cxxabiv1::(anonymous namespace)::PlatformFutexWait, &__cxxabiv1::(anonymous namespace)::PlatformFutexWake, &__cxxabiv1::(anonymous namespace)::PlatformThreadID>::InitByteFutex' requested here
      SelectedImplementation imp(raw_guard_object);
                             ^
    .../llvm-project/libcxxabi/src/cxa_guard_impl.h:416:54: note: prefix with the address-of operator to silence this warning
        has_thread_id_support(this->thread_id_address && GetThreadIDArg),
                                                         ^
                                                         &
    1 error generated.

The diagnostic is incorrect: adding the address-of operator also fails ("cannot
take the address of an rvalue of type 'uint32_t (*)()' (aka 'unsigned int
(*)()')").

Added: 
    

Modified: 
    clang/lib/Sema/SemaTemplate.cpp
    clang/test/SemaCXX/exceptions-seh.cpp
    clang/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 85240e1aeec8..e800f7fe7424 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -6968,77 +6968,100 @@ Sema::BuildExpressionFromDeclTemplateArgument(const TemplateArgument &Arg,
 
   ValueDecl *VD = Arg.getAsDecl();
 
-  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 (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();
 
-  // For a pointer, the argument declaration is the pointee. Take its address.
-  QualType T = RefExpr.get()->getType();
-  bool ObjCLifetimeConversion;
-  if (ParamType->isPointerType() &&
-      (T->isFunctionType() ||
-       (T->isArrayType() &&
-        !Context.hasSameUnqualifiedType(T, ParamType->getPointeeType()) &&
-        !IsQualificationConversion(T, ParamType->getPointeeType(), false,
-                                   ObjCLifetimeConversion)))) {
-    // Decay functions and arrays unless we're forming a pointer to array.
-    RefExpr = DefaultFunctionArrayConversion(RefExpr.get());
-    if (RefExpr.isInvalid())
-      return ExprError();
-  } else if (ParamType->isPointerType() || ParamType->isMemberPointerType()) {
-    RefExpr = CreateBuiltinUnaryOp(Loc, UO_AddrOf, RefExpr.get());
+      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();
+
+  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);
     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 
diff er 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");
+
+    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;
     }
-    RefExpr = ImpCastExprToType(RefExpr.get(), DestExprType, CK,
-                                RefExpr.get()->getValueKind());
+
+    // 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;
   }
 
-  return RefExpr;
+  return BuildDeclRefExpr(VD, T, VK, Loc);
 }
 
 /// 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 02bb786160dc..1d8cc4917e98 100644
--- a/clang/test/SemaCXX/exceptions-seh.cpp
+++ b/clang/test/SemaCXX/exceptions-seh.cpp
@@ -39,13 +39,14 @@ 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(); // expected-error 2{{builtin functions must be directly called}}
+  return FN();
 }
 void inject_builtins() {
-  func_template<void *, __exception_info>(); // expected-note {{instantiation of}}
-  func_template<unsigned long, __exception_code>(); // expected-note {{instantiation of}}
+  func_template<void *, __exception_info>();
+  func_template<unsigned long, __exception_code>();
 }
 #endif
 

diff  --git a/clang/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp b/clang/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp
index 7232598215ac..7a58dd5dcaed 100644
--- a/clang/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp
+++ b/clang/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp
@@ -394,21 +394,6 @@ 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() {
@@ -416,21 +401,4 @@ 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>();
 }


        


More information about the cfe-commits mailing list