]> granicus.if.org Git - clang/commitdiff
When forming a function call or message send expression, be sure to
authorDouglas Gregor <dgregor@apple.com>
Tue, 13 Jul 2010 08:18:22 +0000 (08:18 +0000)
committerDouglas Gregor <dgregor@apple.com>
Tue, 13 Jul 2010 08:18:22 +0000 (08:18 +0000)
strip cv-qualifiers from the expression's type when the language calls
for it: in C, that's all the time, while C++ only does it for
non-class types.

Centralized the computation of the call expression type in
QualType::getCallResultType() and some helper functions in other nodes
(FunctionDecl, ObjCMethodDecl, FunctionType), and updated all relevant
callers of getResultType() to getCallResultType().

Fixes PR7598 and PR7463, along with a bunch of getResultType() call
sites that weren't stripping references off the result type (nothing
stripped cv-qualifiers properly before this change).

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@108234 91177308-0d34-0410-b5e6-96231b3b80d8

24 files changed:
include/clang/AST/Decl.h
include/clang/AST/DeclObjC.h
include/clang/AST/Type.h
include/clang/Basic/DiagnosticSemaKinds.td
lib/AST/Expr.cpp
lib/AST/Type.cpp
lib/Rewrite/RewriteObjC.cpp
lib/Sema/SemaChecking.cpp
lib/Sema/SemaCodeComplete.cpp
lib/Sema/SemaExpr.cpp
lib/Sema/SemaExprCXX.cpp
lib/Sema/SemaExprObjC.cpp
lib/Sema/SemaInit.cpp
lib/Sema/SemaOverload.cpp
lib/Sema/SemaType.cpp
lib/Sema/TreeTransform.h
test/CodeGen/volatile.c
test/Sema/block-call.c
test/Sema/block-return.c
test/Sema/struct-cast.c
test/SemaCXX/ambig-user-defined-conversions.cpp
test/SemaCXX/conditional-expr.cpp
test/SemaCXX/friend.cpp
test/SemaTemplate/deduction.cpp

index d5a7ec029dfb2017648fae8684c671f4b2777c0e..39cd51f606b59537f2a15c87170bae9b5a9ebe6f 100644 (file)
@@ -1382,6 +1382,12 @@ public:
   QualType getResultType() const {
     return getType()->getAs<FunctionType>()->getResultType();
   }
+  
+  /// \brief Determine the type of an expression that calls this function.
+  QualType getCallResultType() const {
+    return getType()->getAs<FunctionType>()->getCallResultType(getASTContext());
+  }
+                       
   StorageClass getStorageClass() const { return StorageClass(SClass); }
   void setStorageClass(StorageClass SC) { SClass = SC; }
 
index b0fd4cc96fbe797f51d3e259f2ed21da42b290f4..fb8596f50a0b3b90df596b729b0e6832a9c99f9f 100644 (file)
@@ -239,6 +239,12 @@ public:
   QualType getResultType() const { return MethodDeclType; }
   void setResultType(QualType T) { MethodDeclType = T; }
 
+  /// \brief Determine the type of an expression that sends a message to this 
+  /// function.
+  QualType getSendResultType() const {
+    return getResultType().getCallResultType(getASTContext());
+  }
+  
   TypeSourceInfo *getResultTypeSourceInfo() const { return ResultTInfo; }
   void setResultTypeSourceInfo(TypeSourceInfo *TInfo) { ResultTInfo = TInfo; }
 
index 8d03641e9dbfc873fb4265b95219e903674d152f..a1a29e6fef6b8468a44de2228120ae452588676d 100644 (file)
@@ -629,6 +629,14 @@ public:
   bool isAtLeastAsQualifiedAs(QualType Other) const;
   QualType getNonReferenceType() const;
 
+  /// \brief Determine the type of an expression that calls a function of
+  /// with the given result type.
+  ///                       
+  /// This routine removes a top-level reference (since there are no 
+  /// expressions of reference type) and deletes top-level cvr-qualifiers
+  /// from non-class types (in C++) or all types (in C).
+  QualType getCallResultType(ASTContext &Context) const;
+  
   /// getDesugaredType - Return the specified type with any "sugar" removed from
   /// the type.  This takes off typedefs, typeof's etc.  If the outer level of
   /// the type is already concrete, it returns it unmodified.  This is similar
@@ -1888,6 +1896,7 @@ protected:
 public:
 
   QualType getResultType() const { return ResultType; }
+  
   unsigned getRegParmType() const { return RegParm; }
   bool getNoReturnAttr() const { return NoReturn; }
   CallingConv getCallConv() const { return (CallingConv)CallConv; }
@@ -1895,6 +1904,12 @@ public:
     return ExtInfo(NoReturn, RegParm, (CallingConv)CallConv);
   }
 
+  /// \brief Determine the type of an expression that calls a function of
+  /// this type.
+  QualType getCallResultType(ASTContext &Context) const { 
+    return getResultType().getCallResultType(Context);
+  }
+
   static llvm::StringRef getNameForCallConv(CallingConv CC);
 
   static bool classof(const Type *T) {
index c56631b4dc1bb0d0aa6a2c6483987e1d998b5287..edd0dcb9159a25d650ccdbfeb59a7488756bf453 100644 (file)
@@ -120,6 +120,8 @@ def warn_use_out_of_scope_declaration : Warning<
   "use of out-of-scope declaration of %0">;
 def err_inline_non_function : Error<
   "'inline' can only appear on functions">;
+def warn_qual_return_type : Warning< 
+  "type qualifier on return type has no effect">;
 
 def warn_decl_shadow :
   Warning<"declaration shadows a %select{"
index cc6ad5ab466bf22ca598639806fe28671f4e28d1..bd97b886fe1e9d40b1dbd0be81eb081d812b4683 100644 (file)
@@ -576,7 +576,10 @@ QualType CallExpr::getCallReturnType() const {
     CalleeType = FnTypePtr->getPointeeType();
   else if (const BlockPointerType *BPT = CalleeType->getAs<BlockPointerType>())
     CalleeType = BPT->getPointeeType();
-
+  else if (const MemberPointerType *MPT
+                                      = CalleeType->getAs<MemberPointerType>())
+    CalleeType = MPT->getPointeeType();
+    
   const FunctionType *FnType = CalleeType->getAs<FunctionType>();
   return FnType->getResultType();
 }
index 5a7aa89d6dfe86ecd81fd696435770493adb3397..ab64eafbee217090880515a9939207ba0855869c 100644 (file)
@@ -992,6 +992,22 @@ const char *BuiltinType::getName(const LangOptions &LO) const {
 
 void FunctionType::ANCHOR() {} // Key function for FunctionType.
 
+QualType QualType::getCallResultType(ASTContext &Context) const {
+  if (const ReferenceType *RefType = getTypePtr()->getAs<ReferenceType>())
+    return RefType->getPointeeType();
+  
+  // C++0x [basic.lval]:
+  //   Class prvalues can have cv-qualified types; non-class prvalues always 
+  //   have cv-unqualified types.
+  //
+  // See also C99 6.3.2.1p2.
+  if (!Context.getLangOptions().CPlusPlus ||
+      !getTypePtr()->isDependentType() && !getTypePtr()->isRecordType())
+    return getUnqualifiedType();
+  
+  return *this;
+}
+
 llvm::StringRef FunctionType::getNameForCallConv(CallingConv CC) {
   switch (CC) {
   case CC_Default: llvm_unreachable("no name for default cc");
index 204ec2641569cd87426312ddecc9f911acf280be..489fec9be0e5fec4229d7444b17eb16d85c70327 100644 (file)
@@ -2113,8 +2113,8 @@ CallExpr *RewriteObjC::SynthesizeCallToFunctionDecl(
   const FunctionType *FT = msgSendType->getAs<FunctionType>();
 
   CallExpr *Exp =  
-    new (Context) CallExpr(*Context, ICE, args, nargs, FT->getResultType(),
-                                EndLoc);
+    new (Context) CallExpr(*Context, ICE, args, nargs, 
+                           FT->getCallResultType(*Context), EndLoc);
   return Exp;
 }
 
index 217ada01c6b8233b91fabdcc60f5835dc62b981e..7a39f058c5ec03e9652a4d06909170186ff4eaf7 100644 (file)
@@ -561,7 +561,7 @@ Sema::SemaBuiltinAtomicOverloaded(OwningExprResult TheCallResult) {
   TheCall->setCallee(PromotedCall);
 
   // Change the result type of the call to match the result type of the decl.
-  TheCall->setType(NewBuiltinDecl->getResultType());
+  TheCall->setType(NewBuiltinDecl->getCallResultType());
 
   // If the value type was converted to an integer when processing the
   // arguments (e.g. void* -> int), we need to convert the result back.
index 6a706dfefe59a9dd76a5c8b805d54f4259547fae..82861101e832d098522fea93fcd926e0e965fc36 100644 (file)
@@ -567,11 +567,11 @@ static QualType getDeclUsageType(ASTContext &C, NamedDecl *ND) {
   
   QualType T;
   if (FunctionDecl *Function = dyn_cast<FunctionDecl>(ND))
-    T = Function->getResultType();
+    T = Function->getCallResultType();
   else if (ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(ND))
-    T = Method->getResultType();
+    T = Method->getSendResultType();
   else if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(ND))
-    T = FunTmpl->getTemplatedDecl()->getResultType();
+    T = FunTmpl->getTemplatedDecl()->getCallResultType();
   else if (EnumConstantDecl *Enumerator = dyn_cast<EnumConstantDecl>(ND))
     T = C.getTypeDeclType(cast<EnumDecl>(Enumerator->getDeclContext()));
   else if (ObjCPropertyDecl *Property = dyn_cast<ObjCPropertyDecl>(ND))
index 9f9858001e621a42b1094c082b767283b654deb5..ce3bf11caa00e2a430737b9eb323caf625140ba3 100644 (file)
@@ -3004,7 +3004,7 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr,
         QualType PType;
 
         if (Getter)
-          PType = Getter->getResultType();
+          PType = Getter->getSendResultType();
         else
           // Get the expression type from Setter's incoming parameter.
           PType = (*(Setter->param_end() -1))->getType();
@@ -3180,7 +3180,7 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr,
           return ExprError();
 
         return Owned(ObjCMessageExpr::Create(Context,
-                                     OMD->getResultType().getNonReferenceType(),
+                                             OMD->getSendResultType(),
                                              OpLoc, BaseExpr, Sel,
                                              OMD, NULL, 0, MemberLoc));
       }
@@ -3575,7 +3575,7 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc,
           BO->getOpcode() == BinaryOperator::PtrMemI) {
         if (const FunctionProtoType *FPT
                                 = BO->getType()->getAs<FunctionProtoType>()) {
-          QualType ResultTy = FPT->getResultType().getNonReferenceType();
+          QualType ResultTy = FPT->getCallResultType(Context);
 
           ExprOwningPtr<CXXMemberCallExpr>
             TheCall(this, new (Context) CXXMemberCallExpr(Context, BO, Args,
@@ -3665,7 +3665,7 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl,
     return ExprError();
 
   // We know the result type of the call, set it.
-  TheCall->setType(FuncT->getResultType().getNonReferenceType());
+  TheCall->setType(FuncT->getCallResultType(Context));
 
   if (const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(FuncT)) {
     if (ConvertArgumentsForCall(&*TheCall, Fn, FDecl, Proto, Args, NumArgs,
index 180b5911bfc42485152d7d67822622f9ee6a52c1..5c693ab358e60fbfbd45055905a95c35f73f3f19 100644 (file)
@@ -3032,7 +3032,7 @@ CXXMemberCallExpr *Sema::BuildCXXMemberCallExpr(Expr *Exp,
   MemberExpr *ME = 
       new (Context) MemberExpr(Exp, /*IsArrow=*/false, Method, 
                                SourceLocation(), Method->getType());
-  QualType ResultType = Method->getResultType().getNonReferenceType();
+  QualType ResultType = Method->getCallResultType();
   MarkDeclarationReferenced(Exp->getLocStart(), Method);
   CXXMemberCallExpr *CE =
     new (Context) CXXMemberCallExpr(Context, ME, 0, 0, ResultType,
index 520ea2af91ba3e1cf4522d6ed910ee8879eb58c3..9f43471e0ade940d6238883e8c90e7e64073c916 100644 (file)
@@ -207,7 +207,7 @@ bool Sema::CheckMessageArgumentTypes(Expr **Args, unsigned NumArgs,
     return false;
   }
 
-  ReturnType = Method->getResultType().getNonReferenceType();
+  ReturnType = Method->getSendResultType();
 
   unsigned NumNamedArgs = Sel.getNumArgs();
   // Method might have more arguments than selector indicates. This is due
@@ -346,7 +346,7 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT,
     Selector Sel = PP.getSelectorTable().getNullarySelector(Member);
     ObjCMethodDecl *Getter = IFace->lookupInstanceMethod(Sel);
     if (DiagnosePropertyAccessorMismatch(PD, Getter, MemberLoc))
-      ResTy = Getter->getResultType();
+      ResTy = Getter->getSendResultType();
     return Owned(new (Context) ObjCPropertyRefExpr(PD, ResTy,
                                                    MemberLoc, BaseExpr));
   }
@@ -402,7 +402,7 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT,
 
   if (Getter) {
     QualType PType;
-    PType = Getter->getResultType();
+    PType = Getter->getSendResultType();
     return Owned(new (Context) ObjCImplicitSetterGetterRefExpr(Getter, PType,
                                     Setter, MemberLoc, BaseExpr));
   }
@@ -510,7 +510,7 @@ ActOnClassPropertyRefExpr(IdentifierInfo &receiverName,
     QualType PType;
 
     if (Getter)
-      PType = Getter->getResultType();
+      PType = Getter->getSendResultType();
     else {
       for (ObjCMethodDecl::param_iterator PI = Setter->param_begin(),
            E = Setter->param_end(); PI != E; ++PI)
index 5571c1b3824e6d0097274de93eba805506e599da..7536289afc10d85f5bce6ffde5f4a676ad4c4feb 100644 (file)
@@ -2942,7 +2942,7 @@ static void TryUserDefinedConversion(Sema &S,
   }
 
   // Add the user-defined conversion step that calls the conversion function.
-  QualType ConvType = Function->getResultType().getNonReferenceType();
+  QualType ConvType = Function->getCallResultType();
   if (ConvType->getAs<RecordType>()) {
     // If we're converting to a class type, there may be an copy if
     // the resulting temporary object (possible to create an object of
index 5b511d7d03c8665f74a61fa1efe8279a0a69e032..ee4c479f728ee4db1fdf35780651643d4b64cd39 100644 (file)
@@ -6668,7 +6668,7 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn,
       DiagnoseUseOfDecl(Best->FoundDecl, OpLoc);
 
       // Determine the result type
-      QualType ResultTy = FnDecl->getResultType().getNonReferenceType();
+      QualType ResultTy = FnDecl->getCallResultType();
 
       // Build the actual expression node.
       Expr *FnExpr = new (Context) DeclRefExpr(FnDecl, FnDecl->getType(),
@@ -6875,8 +6875,8 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
 
         // Determine the result type
         QualType ResultTy
-          = FnDecl->getType()->getAs<FunctionType>()->getResultType();
-        ResultTy = ResultTy.getNonReferenceType();
+          = FnDecl->getType()->getAs<FunctionType>()
+                                                ->getCallResultType(Context);
 
         // Build the actual expression node.
         Expr *FnExpr = new (Context) DeclRefExpr(FnDecl, FnDecl->getType(),
@@ -7032,8 +7032,8 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
 
         // Determine the result type
         QualType ResultTy
-          = FnDecl->getType()->getAs<FunctionType>()->getResultType();
-        ResultTy = ResultTy.getNonReferenceType();
+          = FnDecl->getType()->getAs<FunctionType>()
+                                                  ->getCallResultType(Context);
 
         // Build the actual expression node.
         Expr *FnExpr = new (Context) DeclRefExpr(FnDecl, FnDecl->getType(),
@@ -7221,7 +7221,7 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
   ExprOwningPtr<CXXMemberCallExpr>
     TheCall(this, new (Context) CXXMemberCallExpr(Context, MemExprE, Args,
                                                   NumArgs,
-                                  Method->getResultType().getNonReferenceType(),
+                                  Method->getCallResultType(),
                                   RParenLoc));
 
   // Check for a valid return type.
@@ -7436,7 +7436,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
 
   // Once we've built TheCall, all of the expressions are properly
   // owned.
-  QualType ResultTy = Method->getResultType().getNonReferenceType();
+  QualType ResultTy = Method->getCallResultType();
   ExprOwningPtr<CXXOperatorCallExpr>
     TheCall(this, new (Context) CXXOperatorCallExpr(Context, OO_Call, NewFn,
                                                     MethodArgs, NumArgs + 1,
@@ -7592,7 +7592,7 @@ Sema::BuildOverloadedArrowExpr(Scope *S, ExprArg BaseIn, SourceLocation OpLoc) {
                                            SourceLocation());
   UsualUnaryConversions(FnExpr);
   
-  QualType ResultTy = Method->getResultType().getNonReferenceType();
+  QualType ResultTy = Method->getCallResultType();
   ExprOwningPtr<CXXOperatorCallExpr> 
     TheCall(this, new (Context) CXXOperatorCallExpr(Context, OO_Arrow, FnExpr, 
                                                     &Base, 1, ResultTy, OpLoc));
index 48bf7cbac4e82e68086c7e3444f33725484b3e18..dc3cea1a3c5a85435521a419877daf8272253d3e 100644 (file)
@@ -818,7 +818,7 @@ QualType Sema::BuildFunctionType(QualType T,
       << T->isFunctionType() << T;
     return QualType();
   }
-
+       
   bool Invalid = false;
   for (unsigned Idx = 0; Idx < NumParamTypes; ++Idx) {
     QualType ParamType = adjustParameterType(ParamTypes[Idx]);
@@ -1129,6 +1129,31 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
         D.setInvalidType(true);
       }
 
+      // cv-qualifiers on return types are pointless except when the type is a
+      // class type in C++.
+      if (T.getCVRQualifiers() && D.getDeclSpec().getTypeQualifiers() &&
+          (!getLangOptions().CPlusPlus ||
+           (!T->isDependentType() && !T->isRecordType()))) {
+        unsigned Quals = D.getDeclSpec().getTypeQualifiers();
+        SourceLocation Loc;
+        if (Quals & Qualifiers::Const)
+          Loc = D.getDeclSpec().getConstSpecLoc();
+        else if (Quals & Qualifiers::Volatile)
+          Loc = D.getDeclSpec().getVolatileSpecLoc();
+        else {
+          assert((Quals & Qualifiers::Restrict) && "Unknown type qualifier");
+          Loc = D.getDeclSpec().getRestrictSpecLoc();
+        }
+        
+        SemaDiagnosticBuilder DB = Diag(Loc, diag::warn_qual_return_type);
+        if (Quals & Qualifiers::Const)
+          DB << FixItHint::CreateRemoval(D.getDeclSpec().getConstSpecLoc());
+        if (Quals & Qualifiers::Volatile)
+          DB << FixItHint::CreateRemoval(D.getDeclSpec().getVolatileSpecLoc());
+        if (Quals & Qualifiers::Restrict)
+          DB << FixItHint::CreateRemoval(D.getDeclSpec().getRestrictSpecLoc());
+      }
+      
       if (getLangOptions().CPlusPlus && D.getDeclSpec().isTypeSpecOwned()) {
         // C++ [dcl.fct]p6:
         //   Types shall not be defined in return or parameter types.
index db5e2d10f44140f1d9bd0dcbd225795f41e05ffa..f3ad6c8b4b7cab05d5ffb532125802884b727003 100644 (file)
@@ -1952,7 +1952,7 @@ public:
     Expr **Subs = (Expr **)SubExprs.release();
     CallExpr *TheCall = new (SemaRef.Context) CallExpr(SemaRef.Context, Callee,
                                                        Subs, NumSubExprs,
-                                                       Builtin->getResultType(),
+                                                   Builtin->getCallResultType(),
                                                        RParenLoc);
     OwningExprResult OwnedCall(SemaRef.Owned(TheCall));
 
index db87a375152a69e8485a68550081b5133babe5bb..1a996defcf0107ed34fe502a20112add25905711 100644 (file)
@@ -1,8 +1,8 @@
 // RUN: %clang_cc1 -emit-llvm < %s -o %t
-// RUN: grep volatile %t | count 29
+// RUN: grep volatile %t | count 28
 // RUN: grep memcpy %t | count 7
 
-// The number 29 comes from the current codegen for volatile loads;
+// The number 28 comes from the current codegen for volatile loads;
 // if this number changes, it's not necessarily something wrong, but
 // something has changed to affect volatile load/store codegen
 
@@ -64,7 +64,7 @@ int main() {
   i=vV[3];
   i=VE.yx[1];
   i=vVE.zy[1];
-  i = aggFct().x;
+  i = aggFct().x; // Note: not volatile
   i=vtS;
 
 
index 318bc6b2a3b117acd1ffaa1bc2a9c0119f7d5844..28e6c68a8006900cd8af863480b63663f5913b26 100644 (file)
@@ -13,9 +13,11 @@ int main() {
   int (^IFP) () = PFR; // OK
 
 
-  const int (^CIC) () = IFP; // expected-error {{incompatible block pointer types initializing 'int const (^)()' with an expression of type 'int (^)()'}}
+  const int (^CIC) () = IFP; // expected-error {{incompatible block pointer types initializing 'int const (^)()' with an expression of type 'int (^)()'}} \
+  // expected-warning{{type qualifier on return type has no effect}}
+
+  const int (^CICC) () = CIC;   // expected-warning{{type qualifier on return type has no effect}}
 
-  const int (^CICC) () = CIC;
 
   int * const (^IPCC) () = 0;
 
index 10b3b8480cc9638e09b14f75a37821afca43b2c8..33fd183be069e8fb30cd3cca8f468b08b9660b69 100644 (file)
@@ -109,8 +109,11 @@ void foo6() {
 
 void foo7()
 {
- const int (^BB) (void) = ^{ const int i = 1; return i; }; // expected-error{{incompatible block pointer types initializing 'int const (^)(void)' with an expression of type 'int (^)(void)'}}
- const int (^CC) (void)  = ^const int{ const int i = 1; return i; }; // OK
+ const int (^BB) (void) = ^{ const int i = 1; return i; }; // expected-error{{incompatible block pointer types initializing 'int const (^)(void)' with an expression of type 'int (^)(void)'}} \
+ // expected-warning{{type qualifier on return type has no effect}}
+
+ const int (^CC) (void)  = ^const int{ const int i = 1; return i; }; // expected-warning{{type qualifier on return type has no effect}}
+
 
   int i;
   int (^FF) (void)  = ^{ return i; }; // OK
index dc7db130dc19a4d62d21e4024cfff8958d815cd0..3456665a8c55fc19c46929517a129a273691605f 100644 (file)
@@ -5,7 +5,8 @@ struct S {
  int two;
 };
 
-struct S const foo(void);
+struct S const foo(void);  // expected-warning{{type qualifier on return type has no effect}}
+
 
 struct S tmp;
 
index 7f676748740ccf7a3a50bbde84639b44a783aaf4..9811859fccce0fda58a1b1115c8593f3115447d1 100644 (file)
@@ -17,7 +17,8 @@ namespace test0 {
   void func(const char ci, const B b); // expected-note {{candidate function}}
   void func(const B b, const int ci); // expected-note {{candidate function}}
 
-  const int Test1() {
+  const int Test1() { // expected-warning{{type qualifier on return type has no effect}}
+
     func(b1, f()); // expected-error {{call to 'func' is ambiguous}}
     return f(); // expected-error {{conversion from 'test0::B' to 'int const' is ambiguous}}
   }
index d008b8d6ed72728597304802dcf552b8ede4f558..9cbc324467887d6e792521a05f9685888be28134 100644 (file)
@@ -282,3 +282,20 @@ namespace rdar7998817 {
            : X());
   }
 }
+
+namespace PR7598 {
+  enum Enum {
+    v = 1,
+  };
+
+  const Enum g() { // expected-warning{{type qualifier on return type has no effect}}
+    return v;
+  }
+
+  void f() {
+    const Enum v2 = v;
+    Enum e = false ? g() : v;
+    Enum e2 = false ? v2 : v;
+  }
+
+}
index 4f86d6a94d6bb6fed790abbab9f5202ec6579fca..ba34efe36c2fe44f5ba9713a080c22049fb5a2f5 100644 (file)
@@ -44,7 +44,8 @@ namespace test2 {
 // PR5134
 namespace test3 {
   class Foo {
-    friend const int getInt(int inInt = 0);
+    friend const int getInt(int inInt = 0);   // expected-warning{{type qualifier on return type has no effect}}
+
   };
 }
 
index 8d00bb796e946bd8fd0b3b414d9c1cfe33a24ea7..25ffb67492a564f9cba146d09770e7943179c194 100644 (file)
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only %s
+// RUN: %clang_cc1 -fsyntax-only -verify %s
 
 // Template argument deduction with template template parameters.
 template<typename T, template<T> class A> 
@@ -98,3 +98,10 @@ namespace PR6257 {
   void f(const X<A>& a);
   void test(A& a) { (void)f(a); }
 }
+
+// PR7463
+namespace PR7463 {
+  const int f (); // expected-warning{{type qualifier on return type has no effect}}
+  template <typename T_> void g (T_&); // expected-note{{T_ = int}}
+  void h (void) { g(f()); } // expected-error{{no matching function for call}}
+}