Check for qualified function types after substituting into the operand
authorRichard Smith <richard-llvm@metafoo.co.uk>
Thu, 3 Oct 2019 18:55:23 +0000 (18:55 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Thu, 3 Oct 2019 18:55:23 +0000 (18:55 +0000)
of 'typeid'.

This is a rare place where it's valid for a function type to be
substituted but not valid for a qualified function type to be
substituted, so needs a special check.

llvm-svn: 373648

clang/include/clang/Basic/DiagnosticSemaKinds.td
clang/include/clang/Sema/Sema.h
clang/lib/Sema/SemaExprCXX.cpp
clang/lib/Sema/SemaType.cpp
clang/test/SemaTemplate/instantiate-expr-4.cpp

index 80d8858..b167f46 100644 (file)
@@ -6211,6 +6211,8 @@ def err_invalid_qualified_function_type : Error<
 def err_compound_qualified_function_type : Error<
   "%select{block pointer|pointer|reference}0 to function type %select{%2 |}1"
   "cannot have '%3' qualifier">;
+def err_qualified_function_typeid : Error<
+  "type operand %0 of 'typeid' cannot have '%1' qualifier">;
 
 def err_ref_qualifier_overload : Error<
   "cannot overload a member function %select{without a ref-qualifier|with "
index 1e763bd..402ee4f 100644 (file)
@@ -1522,6 +1522,8 @@ public:
   QualType BuildAddressSpaceAttr(QualType &T, Expr *AddrSpace,
                                  SourceLocation AttrLoc);
 
+  bool CheckQualifiedFunctionForTypeId(QualType T, SourceLocation Loc);
+
   bool CheckFunctionReturnType(QualType T, SourceLocation Loc);
 
   /// Build a function type.
index abd8745..a25e86b 100644 (file)
@@ -453,6 +453,9 @@ ExprResult Sema::BuildCXXTypeId(QualType TypeInfoType,
   if (T->isVariablyModifiedType())
     return ExprError(Diag(TypeidLoc, diag::err_variably_modified_typeid) << T);
 
+  if (CheckQualifiedFunctionForTypeId(T, TypeidLoc))
+    return ExprError();
+
   return new (Context) CXXTypeidExpr(TypeInfoType.withConst(), Operand,
                                      SourceRange(TypeidLoc, RParenLoc));
 }
index a9459d9..3029e14 100644 (file)
@@ -1955,7 +1955,8 @@ static bool checkQualifiedFunction(Sema &S, QualType T, SourceLocation Loc,
                                    QualifiedFunctionKind QFK) {
   // Does T refer to a function type with a cv-qualifier or a ref-qualifier?
   const FunctionProtoType *FPT = T->getAs<FunctionProtoType>();
-  if (!FPT || (FPT->getMethodQuals().empty() && FPT->getRefQualifier() == RQ_None))
+  if (!FPT ||
+      (FPT->getMethodQuals().empty() && FPT->getRefQualifier() == RQ_None))
     return false;
 
   S.Diag(Loc, diag::err_compound_qualified_function_type)
@@ -1964,6 +1965,17 @@ static bool checkQualifiedFunction(Sema &S, QualType T, SourceLocation Loc,
   return true;
 }
 
+bool Sema::CheckQualifiedFunctionForTypeId(QualType T, SourceLocation Loc) {
+  const FunctionProtoType *FPT = T->getAs<FunctionProtoType>();
+  if (!FPT ||
+      (FPT->getMethodQuals().empty() && FPT->getRefQualifier() == RQ_None))
+    return false;
+
+  Diag(Loc, diag::err_qualified_function_typeid)
+      << T << getFunctionQualifiersAsString(FPT);
+  return true;
+}
+
 /// Build a pointer type.
 ///
 /// \param T The type to which we'll be building a pointer.
index 055f37b..6b4eb12 100644 (file)
@@ -192,6 +192,13 @@ struct TypeId0 {
   }
 };
 
+template<typename T>
+struct TypeId1 {
+  const std::type_info &f() {
+    return typeid(T); // expected-error-re 2{{type operand 'void () {{const|&}}' of 'typeid' cannot have '{{const|&}}' qualifier}}
+  }
+};
+
 struct Abstract {
   virtual void f() = 0;
 };
@@ -199,6 +206,8 @@ struct Abstract {
 template struct TypeId0<int>;
 template struct TypeId0<Incomplete>; // expected-note{{instantiation of member function}}
 template struct TypeId0<Abstract>;
+template struct TypeId1<void() const>; // expected-note{{instantiation of}}
+template struct TypeId1<void() &>; // expected-warning 0-1{{C++11}} expected-note{{instantiation of}}
 
 // ---------------------------------------------------------------------
 // type traits