aboutsummaryrefslogtreecommitdiff
path: root/lib/Sema/SemaDecl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Sema/SemaDecl.cpp')
-rw-r--r--lib/Sema/SemaDecl.cpp56
1 files changed, 49 insertions, 7 deletions
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index f7826771cc..06697fafe6 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -2441,12 +2441,22 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S) {
// Certain function declarations cannot be overloaded:
// -- Function declarations that differ only in the return type
// cannot be overloaded.
- QualType OldReturnType = OldType->getResultType();
- QualType NewReturnType = cast<FunctionType>(NewQType)->getResultType();
+
+ // Go back to the type source info to compare the declared return types,
+ // per C++1y [dcl.type.auto]p??:
+ // Redeclarations or specializations of a function or function template
+ // with a declared return type that uses a placeholder type shall also
+ // use that placeholder, not a deduced type.
+ QualType OldDeclaredReturnType = (Old->getTypeSourceInfo()
+ ? Old->getTypeSourceInfo()->getType()->castAs<FunctionType>()
+ : OldType)->getResultType();
+ QualType NewDeclaredReturnType = (New->getTypeSourceInfo()
+ ? New->getTypeSourceInfo()->getType()->castAs<FunctionType>()
+ : NewType)->getResultType();
QualType ResQT;
- if (OldReturnType != NewReturnType) {
- if (NewReturnType->isObjCObjectPointerType()
- && OldReturnType->isObjCObjectPointerType())
+ if (!Context.hasSameType(OldDeclaredReturnType, NewDeclaredReturnType)) {
+ if (NewDeclaredReturnType->isObjCObjectPointerType() &&
+ OldDeclaredReturnType->isObjCObjectPointerType())
ResQT = Context.mergeObjCGCQualifiers(NewQType, OldQType);
if (ResQT.isNull()) {
if (New->isCXXClassMember() && New->isOutOfLine())
@@ -2461,8 +2471,21 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S) {
NewQType = ResQT;
}
- const CXXMethodDecl* OldMethod = dyn_cast<CXXMethodDecl>(Old);
- CXXMethodDecl* NewMethod = dyn_cast<CXXMethodDecl>(New);
+ QualType OldReturnType = OldType->getResultType();
+ QualType NewReturnType = cast<FunctionType>(NewQType)->getResultType();
+ if (OldReturnType != NewReturnType) {
+ // If this function has a deduced return type and has already been
+ // defined, copy the deduced value from the old declaration.
+ AutoType *OldAT = Old->getResultType()->getContainedAutoType();
+ if (OldAT && OldAT->isDeduced()) {
+ New->setType(SubstAutoType(New->getType(), OldAT->getDeducedType()));
+ NewQType = Context.getCanonicalType(
+ SubstAutoType(NewQType, OldAT->getDeducedType()));
+ }
+ }
+
+ const CXXMethodDecl *OldMethod = dyn_cast<CXXMethodDecl>(Old);
+ CXXMethodDecl *NewMethod = dyn_cast<CXXMethodDecl>(New);
if (OldMethod && NewMethod) {
// Preserve triviality.
NewMethod->setTrivial(OldMethod->isTrivial());
@@ -6047,6 +6070,10 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// Okay: Add virtual to the method.
NewFD->setVirtualAsWritten(true);
}
+
+ if (getLangOpts().CPlusPlus1y &&
+ NewFD->getResultType()->isUndeducedType())
+ Diag(D.getDeclSpec().getVirtualSpecLoc(), diag::err_auto_fn_virtual);
}
// C++ [dcl.fct.spec]p3:
@@ -8860,6 +8887,21 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
if (FD) {
FD->setBody(Body);
+ if (getLangOpts().CPlusPlus1y && !FD->isInvalidDecl() &&
+ !FD->isDependentContext()) {
+ if (FD->getResultType()->isUndeducedType()) {
+ // If the function has a deduced result type but contains no 'return'
+ // statements, the result type as written must be exactly 'auto', and
+ // the deduced result type is 'void'.
+ if (!FD->getResultType()->getAs<AutoType>()) {
+ Diag(dcl->getLocation(), diag::err_auto_fn_no_return_but_not_auto)
+ << FD->getResultType();
+ FD->setInvalidDecl();
+ }
+ Context.adjustDeducedFunctionResultType(FD, Context.VoidTy);
+ }
+ }
+
// The only way to be included in UndefinedButUsed is if there is an
// ODR use before the definition. Avoid the expensive map lookup if this
// is the first declaration.