mizvekov updated this revision to Diff 329124.
mizvekov added a comment.

Addressing Arthur's concerns:

- Changed `getBaseDecltypeForExpr` to `getDecltypeForParenthesizedExpr`.
- Changed `ImplicitParens` to `Parenthesized`.
- Clarified comment.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D98160/new/

https://reviews.llvm.org/D98160

Files:
  clang/include/clang/AST/ASTContext.h
  clang/include/clang/AST/Type.h
  clang/include/clang/Sema/Sema.h
  clang/lib/AST/ASTContext.cpp
  clang/lib/AST/Type.cpp
  clang/lib/AST/TypePrinter.cpp
  clang/lib/Sema/SemaConcept.cpp
  clang/lib/Sema/SemaExprCXX.cpp
  clang/lib/Sema/SemaType.cpp
  clang/test/CXX/expr/expr.prim/expr.prim.req/compound-requirement.cpp

Index: clang/test/CXX/expr/expr.prim/expr.prim.req/compound-requirement.cpp
===================================================================
--- clang/test/CXX/expr/expr.prim/expr.prim.req/compound-requirement.cpp
+++ clang/test/CXX/expr/expr.prim/expr.prim.req/compound-requirement.cpp
@@ -79,19 +79,34 @@
 template<typename T>
 constexpr bool is_same_v<T, T> = true;
 
+template<typename T> struct reference {
+	using type = T;
+	static constexpr bool value = false;
+};
+template<typename T> struct reference<T&> {
+	using type = T;
+	static constexpr bool value = true;
+};
+
 template<typename T, typename U>
 concept Same = is_same_v<T, U>;
 
+template<typename T> concept Ref = reference<T>::value;
+
 template<typename T>
-concept Large = sizeof(T) >= 4; // expected-note{{because 'sizeof(short) >= 4' (2 >= 4) evaluated to false}}
+concept LargeRef = sizeof(typename reference<T>::type) >= 4;
+// expected-note@-1{{because 'sizeof(typename reference<short &>::type) >= 4' (2 >= 4) evaluated to false}}
 
-template<typename T> requires requires (T t) { { t } -> Large; } // expected-note{{because 'decltype(t)' (aka 'short') does not satisfy 'Large':}}
+template<typename T> requires requires (T t) {
+  { t } -> Ref;
+  { t } -> LargeRef; // expected-note{{because 'decltype((t))' (aka 'short &') does not satisfy 'LargeRef':}}
+}
 struct r7 {};
 
 using r7i1 = r7<int>;
 using r7i2 = r7<short>; // expected-error{{constraints not satisfied for class template 'r7' [with T = short]}}
 
-template<typename T> requires requires (T t) { { t } -> Same<T>; }
+template<typename T> requires requires (T t) { { t } -> Same<T&>; }
 struct r8 {};
 
 using r8i1 = r8<int>;
@@ -99,7 +114,8 @@
 
 // Substitution failure in type constraint
 
-template<typename T> requires requires (T t) { { t } -> Same<typename T::type>; } // expected-note{{because 'Same<expr-type, typename T::type>' would be invalid: type 'int' cannot be used prior to '::' because it has no members}}
+template<typename T> requires requires (T t) { { t } -> Same<typename T::type&>; }
+// expected-note@-1{{because 'Same<expr-type, typename T::type &>' would be invalid: type 'int' cannot be used prior to '::' because it has no members}}
 struct r9 {};
 
 struct M { using type = M; };
@@ -172,4 +188,4 @@
   static_assert(C5<char>);
   template<C5 T> struct C5_check {}; // expected-note{{because 'short' does not satisfy 'C5'}}
   using c5 = C5_check<short>; // expected-error{{constraints not satisfied for class template 'C5_check' [with T = short]}}
-}
\ No newline at end of file
+}
Index: clang/lib/Sema/SemaType.cpp
===================================================================
--- clang/lib/Sema/SemaType.cpp
+++ clang/lib/Sema/SemaType.cpp
@@ -8833,13 +8833,36 @@
   return Context.getTypeOfExprType(E);
 }
 
+/// getDecltypeForParenthesizedExpr - Given an expr, will return the type for
+/// that expression, as in [dcl.type.simple]p4 but without taking id-expressions
+/// and class member access into account.
+static QualType getDecltypeForParenthesizedExpr(Sema &S, Expr *E) {
+  // C++11 [dcl.type.simple]p4:
+  //   [...]
+  QualType T = E->getType();
+  switch (E->getValueKind()) {
+  //     - otherwise, if e is an xvalue, decltype(e) is T&&, where T is the
+  //       type of e;
+  case VK_XValue:
+    T = S.Context.getRValueReferenceType(T);
+    break;
+  //     - otherwise, if e is an lvalue, decltype(e) is T&, where T is the
+  //       type of e;
+  case VK_LValue:
+    T = S.Context.getLValueReferenceType(T);
+    break;
+  //  - otherwise, decltype(e) is the type of e.
+  case VK_RValue:
+    break;
+  }
+
+  return T;
+}
+
 /// getDecltypeForExpr - Given an expr, will return the decltype for
 /// that expression, according to the rules in C++11
 /// [dcl.type.simple]p4 and C++11 [expr.lambda.prim]p18.
 static QualType getDecltypeForExpr(Sema &S, Expr *E) {
-  if (E->isTypeDependent())
-    return S.Context.DependentTy;
-
   // C++11 [dcl.type.simple]p4:
   //   The type denoted by decltype(e) is defined as follows:
 
@@ -8897,26 +8920,11 @@
     }
   }
 
-
-  // C++11 [dcl.type.simple]p4:
-  //   [...]
-  QualType T = E->getType();
-  switch (E->getValueKind()) {
-  //     - otherwise, if e is an xvalue, decltype(e) is T&&, where T is the
-  //       type of e;
-  case VK_XValue: T = S.Context.getRValueReferenceType(T); break;
-  //     - otherwise, if e is an lvalue, decltype(e) is T&, where T is the
-  //       type of e;
-  case VK_LValue: T = S.Context.getLValueReferenceType(T); break;
-  //  - otherwise, decltype(e) is the type of e.
-  case VK_RValue: break;
-  }
-
-  return T;
+  return getDecltypeForParenthesizedExpr(S, E);
 }
 
 QualType Sema::BuildDecltypeType(Expr *E, SourceLocation Loc,
-                                 bool AsUnevaluated) {
+                                 bool AsUnevaluated, bool Parenthesized) {
   assert(!E->hasPlaceholderType() && "unexpected placeholder");
 
   if (AsUnevaluated && CodeSynthesisContexts.empty() &&
@@ -8928,7 +8936,11 @@
     Diag(E->getExprLoc(), diag::warn_side_effects_unevaluated_context);
   }
 
-  return Context.getDecltypeType(E, getDecltypeForExpr(*this, E));
+  QualType Type = E->isTypeDependent()
+                      ? Context.DependentTy
+                      : (Parenthesized ? getDecltypeForParenthesizedExpr
+                                       : getDecltypeForExpr)(*this, E);
+  return Context.getDecltypeType(E, Type, Parenthesized);
 }
 
 QualType Sema::BuildUnaryTransformType(QualType BaseType,
Index: clang/lib/Sema/SemaExprCXX.cpp
===================================================================
--- clang/lib/Sema/SemaExprCXX.cpp
+++ clang/lib/Sema/SemaExprCXX.cpp
@@ -8640,7 +8640,7 @@
     TemplateParameterList *TPL =
         ReturnTypeRequirement.getTypeConstraintTemplateParameterList();
     QualType MatchedType =
-        BuildDecltypeType(E, E->getBeginLoc()).getCanonicalType();
+        BuildDecltypeType(E, E->getBeginLoc(), true, true).getCanonicalType();
     llvm::SmallVector<TemplateArgument, 1> Args;
     Args.push_back(TemplateArgument(MatchedType));
     TemplateArgumentList TAL(TemplateArgumentList::OnStack, Args);
Index: clang/lib/Sema/SemaConcept.cpp
===================================================================
--- clang/lib/Sema/SemaConcept.cpp
+++ clang/lib/Sema/SemaConcept.cpp
@@ -444,8 +444,9 @@
         // was not provided arguments.
         S.Diag(ConstraintExpr->getBeginLoc(),
                diag::note_expr_requirement_constraints_not_satisfied_simple)
-            << (int)First << S.BuildDecltypeType(Req->getExpr(),
-                                                 Req->getExpr()->getBeginLoc())
+            << (int)First
+            << S.BuildDecltypeType(Req->getExpr(),
+                                   Req->getExpr()->getBeginLoc(), true, true)
             << ConstraintExpr->getNamedConcept();
       else
         S.Diag(ConstraintExpr->getBeginLoc(),
Index: clang/lib/AST/TypePrinter.cpp
===================================================================
--- clang/lib/AST/TypePrinter.cpp
+++ clang/lib/AST/TypePrinter.cpp
@@ -1083,8 +1083,12 @@
 
 void TypePrinter::printDecltypeBefore(const DecltypeType *T, raw_ostream &OS) {
   OS << "decltype(";
+  if (T->getParenthesized())
+    OS << "(";
   if (T->getUnderlyingExpr())
     T->getUnderlyingExpr()->printPretty(OS, nullptr, Policy);
+  if (T->getParenthesized())
+    OS << ")";
   OS << ')';
   spaceBeforePlaceHolder(OS);
 }
Index: clang/lib/AST/Type.cpp
===================================================================
--- clang/lib/AST/Type.cpp
+++ clang/lib/AST/Type.cpp
@@ -3423,7 +3423,8 @@
   E->Profile(ID, Context, true);
 }
 
-DecltypeType::DecltypeType(Expr *E, QualType underlyingType, QualType can)
+DecltypeType::DecltypeType(Expr *E, QualType underlyingType, QualType can,
+                           bool Parenthesized)
     // C++11 [temp.type]p2: "If an expression e involves a template parameter,
     // decltype(e) denotes a unique dependent type." Hence a decltype type is
     // type-dependent even if its expression is only instantiation-dependent.
@@ -3433,7 +3434,7 @@
                                               : TypeDependence::None) |
                (E->getType()->getDependence() &
                 TypeDependence::VariablyModified)),
-      E(E), UnderlyingType(underlyingType) {}
+      E(E), UnderlyingType(underlyingType), Parenthesized(Parenthesized) {}
 
 bool DecltypeType::isSugared() const { return !E->isInstantiationDependent(); }
 
Index: clang/lib/AST/ASTContext.cpp
===================================================================
--- clang/lib/AST/ASTContext.cpp
+++ clang/lib/AST/ASTContext.cpp
@@ -5426,7 +5426,8 @@
 /// nodes. This would never be helpful, since each such type has its own
 /// expression, and would not give a significant memory saving, since there
 /// is an Expr tree under each such type.
-QualType ASTContext::getDecltypeType(Expr *e, QualType UnderlyingType) const {
+QualType ASTContext::getDecltypeType(Expr *e, QualType UnderlyingType,
+                                     bool Parenthesized) const {
   DecltypeType *dt;
 
   // C++11 [temp.type]p2:
@@ -5445,11 +5446,11 @@
       Canon = new (*this, TypeAlignment) DependentDecltypeType(*this, e);
       DependentDecltypeTypes.InsertNode(Canon, InsertPos);
     }
-    dt = new (*this, TypeAlignment)
-        DecltypeType(e, UnderlyingType, QualType((DecltypeType *)Canon, 0));
+    dt = new (*this, TypeAlignment) DecltypeType(
+        e, UnderlyingType, QualType((DecltypeType *)Canon, 0), Parenthesized);
   } else {
-    dt = new (*this, TypeAlignment)
-        DecltypeType(e, UnderlyingType, getCanonicalType(UnderlyingType));
+    dt = new (*this, TypeAlignment) DecltypeType(
+        e, UnderlyingType, getCanonicalType(UnderlyingType), Parenthesized);
   }
   Types.push_back(dt);
   return QualType(dt, 0);
Index: clang/include/clang/Sema/Sema.h
===================================================================
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -2288,7 +2288,8 @@
   /// If AsUnevaluated is false, E is treated as though it were an evaluated
   /// context, such as when building a type for decltype(auto).
   QualType BuildDecltypeType(Expr *E, SourceLocation Loc,
-                             bool AsUnevaluated = true);
+                             bool AsUnevaluated = true,
+                             bool Parenthesized = false);
   QualType BuildUnaryTransformType(QualType BaseType,
                                    UnaryTransformType::UTTKind UKind,
                                    SourceLocation Loc);
Index: clang/include/clang/AST/Type.h
===================================================================
--- clang/include/clang/AST/Type.h
+++ clang/include/clang/AST/Type.h
@@ -4483,15 +4483,18 @@
 class DecltypeType : public Type {
   Expr *E;
   QualType UnderlyingType;
+  bool Parenthesized;
 
 protected:
   friend class ASTContext; // ASTContext creates these.
 
-  DecltypeType(Expr *E, QualType underlyingType, QualType can = QualType());
+  DecltypeType(Expr *E, QualType underlyingType, QualType can = QualType(),
+               bool Parenthesized = false);
 
 public:
   Expr *getUnderlyingExpr() const { return E; }
   QualType getUnderlyingType() const { return UnderlyingType; }
+  bool getParenthesized() const { return Parenthesized; }
 
   /// Remove a single level of sugar.
   QualType desugar() const;
Index: clang/include/clang/AST/ASTContext.h
===================================================================
--- clang/include/clang/AST/ASTContext.h
+++ clang/include/clang/AST/ASTContext.h
@@ -1560,7 +1560,8 @@
   QualType getTypeOfType(QualType t) const;
 
   /// C++11 decltype.
-  QualType getDecltypeType(Expr *e, QualType UnderlyingType) const;
+  QualType getDecltypeType(Expr *e, QualType UnderlyingType,
+                           bool Parenthesized = false) const;
 
   /// Unary type transforms
   QualType getUnaryTransformType(QualType BaseType, QualType UnderlyingType,
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to