diff options
24 files changed, 143 insertions, 38 deletions
diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h index d5a7ec029df..39cd51f606b 100644 --- a/clang/include/clang/AST/Decl.h +++ b/clang/include/clang/AST/Decl.h @@ -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; } diff --git a/clang/include/clang/AST/DeclObjC.h b/clang/include/clang/AST/DeclObjC.h index b0fd4cc96fb..fb8596f50a0 100644 --- a/clang/include/clang/AST/DeclObjC.h +++ b/clang/include/clang/AST/DeclObjC.h @@ -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; } diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index 8d03641e9db..a1a29e6fef6 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -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) { diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index c56631b4dc1..edd0dcb9159 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -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{" diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index cc6ad5ab466..bd97b886fe1 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -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(); } diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index 5a7aa89d6df..ab64eafbee2 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -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"); diff --git a/clang/lib/Rewrite/RewriteObjC.cpp b/clang/lib/Rewrite/RewriteObjC.cpp index 204ec264156..489fec9be0e 100644 --- a/clang/lib/Rewrite/RewriteObjC.cpp +++ b/clang/lib/Rewrite/RewriteObjC.cpp @@ -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; } diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 217ada01c6b..7a39f058c5e 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -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. diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp index 6a706dfefe5..82861101e83 100644 --- a/clang/lib/Sema/SemaCodeComplete.cpp +++ b/clang/lib/Sema/SemaCodeComplete.cpp @@ -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)) diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 9f9858001e6..ce3bf11caa0 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -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, diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index 180b5911bfc..5c693ab358e 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -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, diff --git a/clang/lib/Sema/SemaExprObjC.cpp b/clang/lib/Sema/SemaExprObjC.cpp index 520ea2af91b..9f43471e0ad 100644 --- a/clang/lib/Sema/SemaExprObjC.cpp +++ b/clang/lib/Sema/SemaExprObjC.cpp @@ -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) diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index 5571c1b3824..7536289afc1 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -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 diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 5b511d7d03c..ee4c479f728 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -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)); diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 48bf7cbac4e..dc3cea1a3c5 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -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. diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index db5e2d10f44..f3ad6c8b4b7 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -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)); diff --git a/clang/test/CodeGen/volatile.c b/clang/test/CodeGen/volatile.c index db87a375152..1a996defcf0 100644 --- a/clang/test/CodeGen/volatile.c +++ b/clang/test/CodeGen/volatile.c @@ -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; diff --git a/clang/test/Sema/block-call.c b/clang/test/Sema/block-call.c index 318bc6b2a3b..28e6c68a800 100644 --- a/clang/test/Sema/block-call.c +++ b/clang/test/Sema/block-call.c @@ -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; diff --git a/clang/test/Sema/block-return.c b/clang/test/Sema/block-return.c index 10b3b8480cc..33fd183be06 100644 --- a/clang/test/Sema/block-return.c +++ b/clang/test/Sema/block-return.c @@ -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 diff --git a/clang/test/Sema/struct-cast.c b/clang/test/Sema/struct-cast.c index dc7db130dc1..3456665a8c5 100644 --- a/clang/test/Sema/struct-cast.c +++ b/clang/test/Sema/struct-cast.c @@ -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; diff --git a/clang/test/SemaCXX/ambig-user-defined-conversions.cpp b/clang/test/SemaCXX/ambig-user-defined-conversions.cpp index 7f676748740..9811859fccc 100644 --- a/clang/test/SemaCXX/ambig-user-defined-conversions.cpp +++ b/clang/test/SemaCXX/ambig-user-defined-conversions.cpp @@ -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}} } diff --git a/clang/test/SemaCXX/conditional-expr.cpp b/clang/test/SemaCXX/conditional-expr.cpp index d008b8d6ed7..9cbc3244678 100644 --- a/clang/test/SemaCXX/conditional-expr.cpp +++ b/clang/test/SemaCXX/conditional-expr.cpp @@ -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; + } + +} diff --git a/clang/test/SemaCXX/friend.cpp b/clang/test/SemaCXX/friend.cpp index 4f86d6a94d6..ba34efe36c2 100644 --- a/clang/test/SemaCXX/friend.cpp +++ b/clang/test/SemaCXX/friend.cpp @@ -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}} + }; } diff --git a/clang/test/SemaTemplate/deduction.cpp b/clang/test/SemaTemplate/deduction.cpp index 8d00bb796e9..25ffb67492a 100644 --- a/clang/test/SemaTemplate/deduction.cpp +++ b/clang/test/SemaTemplate/deduction.cpp @@ -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}} +} |