courbet created this revision. courbet added reviewers: rsmith, aaron.ballman. courbet requested review of this revision. Herald added a project: clang.
Example: template <typename T> auto f(T* t) { return *t; } Before that change, the `UnaryOperator` for `*t` has type `<dependent type>`. After the change, its type is a `T` lvalue. I've added simple tests to verify that giving knowledge of the type to clang does not yields false positives in contexts where c++ does not allow it to use that knowledge. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D112453 Files: clang/lib/Sema/SemaOverload.cpp clang/test/SemaTemplate/dependent-type-identity.cpp Index: clang/test/SemaTemplate/dependent-type-identity.cpp =================================================================== --- clang/test/SemaTemplate/dependent-type-identity.cpp +++ clang/test/SemaTemplate/dependent-type-identity.cpp @@ -69,6 +69,16 @@ void f8(typename N::X2<U>::template apply<U> *); void f8(typename N::X2<U>::template apply<T> *); void f8(typename ::Nalias::X2<type>::template apply<U_type> *); // expected-error{{redeclar}} + + // (17.4.2): If an expression e is type-dependent (17.6.2.2), decltype(e) + // denotes a unique dependent type. Two such decltype-specifiers refer to the + // same type only if their expressions are equivalent (17.5.6.1) + T* a; + T* b; + using V = decltype(*a); + void f9(decltype(*a)); // expected-note{{previous}} + void f9(decltype(*b)); + void f9(V); // expected-error{{redeclar}} }; namespace PR6851 { Index: clang/lib/Sema/SemaOverload.cpp =================================================================== --- clang/lib/Sema/SemaOverload.cpp +++ clang/lib/Sema/SemaOverload.cpp @@ -13323,10 +13323,22 @@ ArrayRef<Expr *> ArgsArray(Args, NumArgs); if (Input->isTypeDependent()) { - if (Fns.empty()) - return UnaryOperator::Create(Context, Input, Opc, Context.DependentTy, - VK_PRValue, OK_Ordinary, OpLoc, false, + if (Fns.empty()) { + QualType ResultTy = Context.DependentTy; + ExprValueKind ResultKind = VK_PRValue; + if (getLangOpts().CPlusPlus && (Opc == UO_Deref) && + Input->getType()->isPointerType()) { + // In c++, a deref of a `T*` always has type `T&` (16.6.8). There is no + // way for other overloads to be selected since overloads of `operator*` + // always have class or enum parameters. + ResultTy = cast<PointerType>(Input->getType().getCanonicalType()) + ->getPointeeType(); + ResultKind = VK_LValue; + } + return UnaryOperator::Create(Context, Input, Opc, ResultTy, ResultKind, + OK_Ordinary, OpLoc, false, CurFPFeatureOverrides()); + } CXXRecordDecl *NamingClass = nullptr; // lookup ignores member operators ExprResult Fn = CreateUnresolvedLookupExpr(
Index: clang/test/SemaTemplate/dependent-type-identity.cpp =================================================================== --- clang/test/SemaTemplate/dependent-type-identity.cpp +++ clang/test/SemaTemplate/dependent-type-identity.cpp @@ -69,6 +69,16 @@ void f8(typename N::X2<U>::template apply<U> *); void f8(typename N::X2<U>::template apply<T> *); void f8(typename ::Nalias::X2<type>::template apply<U_type> *); // expected-error{{redeclar}} + + // (17.4.2): If an expression e is type-dependent (17.6.2.2), decltype(e) + // denotes a unique dependent type. Two such decltype-specifiers refer to the + // same type only if their expressions are equivalent (17.5.6.1) + T* a; + T* b; + using V = decltype(*a); + void f9(decltype(*a)); // expected-note{{previous}} + void f9(decltype(*b)); + void f9(V); // expected-error{{redeclar}} }; namespace PR6851 { Index: clang/lib/Sema/SemaOverload.cpp =================================================================== --- clang/lib/Sema/SemaOverload.cpp +++ clang/lib/Sema/SemaOverload.cpp @@ -13323,10 +13323,22 @@ ArrayRef<Expr *> ArgsArray(Args, NumArgs); if (Input->isTypeDependent()) { - if (Fns.empty()) - return UnaryOperator::Create(Context, Input, Opc, Context.DependentTy, - VK_PRValue, OK_Ordinary, OpLoc, false, + if (Fns.empty()) { + QualType ResultTy = Context.DependentTy; + ExprValueKind ResultKind = VK_PRValue; + if (getLangOpts().CPlusPlus && (Opc == UO_Deref) && + Input->getType()->isPointerType()) { + // In c++, a deref of a `T*` always has type `T&` (16.6.8). There is no + // way for other overloads to be selected since overloads of `operator*` + // always have class or enum parameters. + ResultTy = cast<PointerType>(Input->getType().getCanonicalType()) + ->getPointeeType(); + ResultKind = VK_LValue; + } + return UnaryOperator::Create(Context, Input, Opc, ResultTy, ResultKind, + OK_Ordinary, OpLoc, false, CurFPFeatureOverrides()); + } CXXRecordDecl *NamingClass = nullptr; // lookup ignores member operators ExprResult Fn = CreateUnresolvedLookupExpr(
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits