aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2018-11-04 14:42:02 +0000
committerDimitry Andric <dim@FreeBSD.org>2018-11-04 14:42:02 +0000
commitce9602e2894244cc7e2915acfd50d783b2d4f949 (patch)
tree27c94a584d4830e271fcce73ab31cd43d828a15a
parentf10971f5ff4df3ff41ab6728a338522b945e4b40 (diff)
Vendor import of clang release_70 branch r346007:vendor/clang/clang-release_70-r346007
Notes
Notes: svn path=/vendor/clang/dist-release_70/; revision=340118 svn path=/vendor/clang/clang-release_70-r346007/; revision=340119; tag=vendor/clang/clang-release_70-r346007
-rw-r--r--bindings/python/tests/cindex/test_code_completion.py8
-rw-r--r--include/clang/AST/Decl.h15
-rw-r--r--include/clang/Driver/Options.td2
-rw-r--r--include/clang/Sema/Sema.h2
-rw-r--r--lib/Basic/Version.cpp2
-rw-r--r--lib/CodeGen/CGBuiltin.cpp6
-rw-r--r--lib/Driver/Driver.cpp7
-rw-r--r--lib/Driver/ToolChains/Gnu.cpp2
-rw-r--r--lib/Sema/SemaDecl.cpp90
-rw-r--r--lib/Sema/SemaOverload.cpp3
-rw-r--r--lib/Sema/SemaTemplate.cpp2
-rw-r--r--test/CodeGen/attr-target-mv.c17
-rw-r--r--test/CodeGen/builtin-cpu-supports.c2
-rw-r--r--test/Driver/cl-options.c1
-rw-r--r--test/Driver/cl-pch.cpp21
-rw-r--r--test/Driver/linux-ld.c8
-rw-r--r--test/PCH/Inputs/pch-through-use3c.cpp2
-rw-r--r--test/PCH/Inputs/pch-through3c.h1
-rw-r--r--test/PCH/pch-through3c.cpp8
-rw-r--r--test/SemaCXX/cxx1y-deduced-return-type.cpp70
-rw-r--r--test/SemaCXX/friend.cpp23
21 files changed, 245 insertions, 47 deletions
diff --git a/bindings/python/tests/cindex/test_code_completion.py b/bindings/python/tests/cindex/test_code_completion.py
index a56bb304cd71..efc7912c915d 100644
--- a/bindings/python/tests/cindex/test_code_completion.py
+++ b/bindings/python/tests/cindex/test_code_completion.py
@@ -61,11 +61,11 @@ void f(P x, Q y) {
cr = tu.codeComplete('fake.cpp', 12, 5, unsaved_files=files)
expected = [
- "{'const', TypedText} || Priority: 40 || Availability: Available || Brief comment: None",
- "{'volatile', TypedText} || Priority: 40 || Availability: Available || Brief comment: None",
+ "{'const', TypedText} || Priority: 50 || Availability: Available || Brief comment: None",
+ "{'volatile', TypedText} || Priority: 50 || Availability: Available || Brief comment: None",
"{'operator', TypedText} || Priority: 40 || Availability: Available || Brief comment: None",
- "{'P', TypedText} | {'::', Text} || Priority: 75 || Availability: Available || Brief comment: None",
- "{'Q', TypedText} | {'::', Text} || Priority: 75 || Availability: Available || Brief comment: None"
+ "{'P', TypedText} || Priority: 50 || Availability: Available || Brief comment: None",
+ "{'Q', TypedText} || Priority: 50 || Availability: Available || Brief comment: None"
]
self.check_completion_results(cr, expected)
diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h
index 6885968bae60..29284435ebe0 100644
--- a/include/clang/AST/Decl.h
+++ b/include/clang/AST/Decl.h
@@ -2269,8 +2269,7 @@ public:
unsigned getMinRequiredArguments() const;
QualType getReturnType() const {
- assert(getType()->getAs<FunctionType>() && "Expected a FunctionType!");
- return getType()->getAs<FunctionType>()->getReturnType();
+ return getType()->castAs<FunctionType>()->getReturnType();
}
/// Attempt to compute an informative source range covering the
@@ -2278,14 +2277,22 @@ public:
/// limited representation in the AST.
SourceRange getReturnTypeSourceRange() const;
+ /// Get the declared return type, which may differ from the actual return
+ /// type if the return type is deduced.
+ QualType getDeclaredReturnType() const {
+ auto *TSI = getTypeSourceInfo();
+ QualType T = TSI ? TSI->getType() : getType();
+ return T->castAs<FunctionType>()->getReturnType();
+ }
+
/// Attempt to compute an informative source range covering the
/// function exception specification, if any.
SourceRange getExceptionSpecSourceRange() const;
/// Determine the type of an expression that calls this function.
QualType getCallResultType() const {
- assert(getType()->getAs<FunctionType>() && "Expected a FunctionType!");
- return getType()->getAs<FunctionType>()->getCallResultType(getASTContext());
+ return getType()->castAs<FunctionType>()->getCallResultType(
+ getASTContext());
}
/// Returns the WarnUnusedResultAttr that is either declared on this
diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td
index 7da45d277490..601aa8744967 100644
--- a/include/clang/Driver/Options.td
+++ b/include/clang/Driver/Options.td
@@ -802,7 +802,7 @@ def fconstexpr_backtrace_limit_EQ : Joined<["-"], "fconstexpr-backtrace-limit=">
Group<f_Group>;
def fno_crash_diagnostics : Flag<["-"], "fno-crash-diagnostics">, Group<f_clang_Group>, Flags<[NoArgumentUnused]>,
HelpText<"Disable auto-generation of preprocessed source files and a script for reproduction during a clang crash">;
-def fcrash_diagnostics_dir : Joined<["-"], "fcrash-diagnostics-dir=">, Group<f_clang_Group>, Flags<[NoArgumentUnused]>;
+def fcrash_diagnostics_dir : Joined<["-"], "fcrash-diagnostics-dir=">, Group<f_clang_Group>, Flags<[NoArgumentUnused, CoreOption]>;
def fcreate_profile : Flag<["-"], "fcreate-profile">, Group<f_Group>;
def fcxx_exceptions: Flag<["-"], "fcxx-exceptions">, Group<f_Group>,
HelpText<"Enable C++ exceptions">, Flags<[CC1Option]>;
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index b1077c620f8a..2365b596e8db 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -1950,6 +1950,8 @@ public:
FunctionDecl *NewFD, LookupResult &Previous,
bool IsMemberSpecialization);
bool shouldLinkDependentDeclWithPrevious(Decl *D, Decl *OldDecl);
+ bool canFullyTypeCheckRedeclaration(ValueDecl *NewD, ValueDecl *OldD,
+ QualType NewT, QualType OldT);
void CheckMain(FunctionDecl *FD, const DeclSpec &D);
void CheckMSVCRTEntryPoint(FunctionDecl *FD);
Attr *getImplicitCodeSegOrSectionAttrForFunction(const FunctionDecl *FD, bool IsDefinition);
diff --git a/lib/Basic/Version.cpp b/lib/Basic/Version.cpp
index 3fcdc568c0f3..badf5d9dec52 100644
--- a/lib/Basic/Version.cpp
+++ b/lib/Basic/Version.cpp
@@ -36,7 +36,7 @@ std::string getClangRepositoryPath() {
// If the SVN_REPOSITORY is empty, try to use the SVN keyword. This helps us
// pick up a tag in an SVN export, for example.
- StringRef SVNRepository("$URL: https://llvm.org/svn/llvm-project/cfe/tags/RELEASE_700/final/lib/Basic/Version.cpp $");
+ StringRef SVNRepository("$URL: https://llvm.org/svn/llvm-project/cfe/branches/release_70/lib/Basic/Version.cpp $");
if (URL.empty()) {
URL = SVNRepository.slice(SVNRepository.find(':'),
SVNRepository.find("/lib/Basic"));
diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp
index 669a3be0e6e1..0770c204dab1 100644
--- a/lib/CodeGen/CGBuiltin.cpp
+++ b/lib/CodeGen/CGBuiltin.cpp
@@ -8952,9 +8952,9 @@ llvm::Value *CodeGenFunction::EmitX86CpuSupports(uint32_t FeaturesMask) {
Builder.CreateAlignedLoad(CpuFeatures, CharUnits::fromQuantity(4));
// Check the value of the bit corresponding to the feature requested.
- Value *Bitset = Builder.CreateAnd(
- Features, llvm::ConstantInt::get(Int32Ty, FeaturesMask));
- return Builder.CreateICmpNE(Bitset, llvm::ConstantInt::get(Int32Ty, 0));
+ Value *Mask = Builder.getInt32(FeaturesMask);
+ Value *Bitset = Builder.CreateAnd(Features, Mask);
+ return Builder.CreateICmpEQ(Bitset, Mask);
}
Value *CodeGenFunction::EmitX86CpuInit() {
diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp
index 952a716cb6e6..b69d65ea907a 100644
--- a/lib/Driver/Driver.cpp
+++ b/lib/Driver/Driver.cpp
@@ -2998,9 +2998,10 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args,
Args.eraseArg(options::OPT__SLASH_Yc);
YcArg = nullptr;
}
- if (Args.hasArg(options::OPT__SLASH_Y_)) {
- // /Y- disables all pch handling. Rather than check for it everywhere,
- // just remove clang-cl pch-related flags here.
+ if (FinalPhase == phases::Preprocess || Args.hasArg(options::OPT__SLASH_Y_)) {
+ // If only preprocessing or /Y- is used, all pch handling is disabled.
+ // Rather than check for it everywhere, just remove clang-cl pch-related
+ // flags here.
Args.eraseArg(options::OPT__SLASH_Fp);
Args.eraseArg(options::OPT__SLASH_Yc);
Args.eraseArg(options::OPT__SLASH_Yu);
diff --git a/lib/Driver/ToolChains/Gnu.cpp b/lib/Driver/ToolChains/Gnu.cpp
index 3755673250b2..66fa21402d71 100644
--- a/lib/Driver/ToolChains/Gnu.cpp
+++ b/lib/Driver/ToolChains/Gnu.cpp
@@ -237,7 +237,7 @@ static const char *getLDMOption(const llvm::Triple &T, const ArgList &Args) {
case llvm::Triple::aarch64:
return "aarch64linux";
case llvm::Triple::aarch64_be:
- return "aarch64_be_linux";
+ return "aarch64linuxb";
case llvm::Triple::arm:
case llvm::Triple::thumb:
return "armelf_linux_eabi";
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index b92d76ad4204..40384fa6a433 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -3249,20 +3249,15 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD,
// 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)->getReturnType();
- QualType NewDeclaredReturnType =
- (New->getTypeSourceInfo()
- ? New->getTypeSourceInfo()->getType()->castAs<FunctionType>()
- : NewType)->getReturnType();
+ QualType OldDeclaredReturnType = Old->getDeclaredReturnType();
+ QualType NewDeclaredReturnType = New->getDeclaredReturnType();
if (!Context.hasSameType(OldDeclaredReturnType, NewDeclaredReturnType) &&
- !((NewQType->isDependentType() || OldQType->isDependentType()) &&
- New->isLocalExternDecl())) {
+ canFullyTypeCheckRedeclaration(New, Old, NewDeclaredReturnType,
+ OldDeclaredReturnType)) {
QualType ResQT;
if (NewDeclaredReturnType->isObjCObjectPointerType() &&
OldDeclaredReturnType->isObjCObjectPointerType())
+ // FIXME: This does the wrong thing for a deduced return type.
ResQT = Context.mergeObjCGCQualifiers(NewQType, OldQType);
if (ResQT.isNull()) {
if (New->isCXXClassMember() && New->isOutOfLine())
@@ -3427,13 +3422,11 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD,
if (OldQTypeForComparison == NewQType)
return MergeCompatibleFunctionDecls(New, Old, S, MergeTypeWithOld);
- if ((NewQType->isDependentType() || OldQType->isDependentType()) &&
- New->isLocalExternDecl()) {
- // It's OK if we couldn't merge types for a local function declaraton
- // if either the old or new type is dependent. We'll merge the types
- // when we instantiate the function.
+ // If the types are imprecise (due to dependent constructs in friends or
+ // local extern declarations), it's OK if they differ. We'll check again
+ // during instantiation.
+ if (!canFullyTypeCheckRedeclaration(New, Old, NewQType, OldQType))
return false;
- }
// Fall through for conflicting redeclarations and redefinitions.
}
@@ -9336,6 +9329,39 @@ Attr *Sema::getImplicitCodeSegOrSectionAttrForFunction(const FunctionDecl *FD,
}
return nullptr;
}
+
+/// Determines if we can perform a correct type check for \p D as a
+/// redeclaration of \p PrevDecl. If not, we can generally still perform a
+/// best-effort check.
+///
+/// \param NewD The new declaration.
+/// \param OldD The old declaration.
+/// \param NewT The portion of the type of the new declaration to check.
+/// \param OldT The portion of the type of the old declaration to check.
+bool Sema::canFullyTypeCheckRedeclaration(ValueDecl *NewD, ValueDecl *OldD,
+ QualType NewT, QualType OldT) {
+ if (!NewD->getLexicalDeclContext()->isDependentContext())
+ return true;
+
+ // For dependently-typed local extern declarations and friends, we can't
+ // perform a correct type check in general until instantiation:
+ //
+ // int f();
+ // template<typename T> void g() { T f(); }
+ //
+ // (valid if g() is only instantiated with T = int).
+ if (NewT->isDependentType() &&
+ (NewD->isLocalExternDecl() || NewD->getFriendObjectKind()))
+ return false;
+
+ // Similarly, if the previous declaration was a dependent local extern
+ // declaration, we don't really know its type yet.
+ if (OldT->isDependentType() && OldD->isLocalExternDecl())
+ return false;
+
+ return true;
+}
+
/// Checks if the new declaration declared in dependent context must be
/// put in the same redeclaration chain as the specified declaration.
///
@@ -9346,20 +9372,30 @@ Attr *Sema::getImplicitCodeSegOrSectionAttrForFunction(const FunctionDecl *FD,
/// belongs to.
///
bool Sema::shouldLinkDependentDeclWithPrevious(Decl *D, Decl *PrevDecl) {
- // Any declarations should be put into redeclaration chains except for
- // friend declaration in a dependent context that names a function in
- // namespace scope.
+ if (!D->getLexicalDeclContext()->isDependentContext())
+ return true;
+
+ // Don't chain dependent friend function definitions until instantiation, to
+ // permit cases like
//
- // This allows to compile code like:
+ // void func();
+ // template<typename T> class C1 { friend void func() {} };
+ // template<typename T> class C2 { friend void func() {} };
//
- // void func();
- // template<typename T> class C1 { friend void func() { } };
- // template<typename T> class C2 { friend void func() { } };
+ // ... which is valid if only one of C1 and C2 is ever instantiated.
//
- // This code snippet is a valid code unless both templates are instantiated.
- return !(D->getLexicalDeclContext()->isDependentContext() &&
- D->getDeclContext()->isFileContext() &&
- D->getFriendObjectKind() != Decl::FOK_None);
+ // FIXME: This need only apply to function definitions. For now, we proxy
+ // this by checking for a file-scope function. We do not want this to apply
+ // to friend declarations nominating member functions, because that gets in
+ // the way of access checks.
+ if (D->getFriendObjectKind() && D->getDeclContext()->isFileContext())
+ return false;
+
+ auto *VD = dyn_cast<ValueDecl>(D);
+ auto *PrevVD = dyn_cast<ValueDecl>(PrevDecl);
+ return !VD || !PrevVD ||
+ canFullyTypeCheckRedeclaration(VD, PrevVD, VD->getType(),
+ PrevVD->getType());
}
namespace MultiVersioning {
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index 08af485ef4c7..244c66f6939d 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -1105,7 +1105,8 @@ bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old,
(!TemplateParameterListsAreEqual(NewTemplate->getTemplateParameters(),
OldTemplate->getTemplateParameters(),
false, TPL_TemplateMatch) ||
- OldType->getReturnType() != NewType->getReturnType()))
+ !Context.hasSameType(Old->getDeclaredReturnType(),
+ New->getDeclaredReturnType())))
return true;
// If the function is a class member, its signature includes the
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index fa002de3f5f1..9d6cd7d555db 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -8304,6 +8304,8 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) {
QualType Adjusted = Function->getType();
if (!hasExplicitCallingConv(Adjusted))
Adjusted = adjustCCAndNoReturn(Adjusted, Method->getType());
+ // This doesn't handle deduced return types, but both function
+ // declarations should be undeduced at this point.
if (Context.hasSameType(Adjusted, Method->getType())) {
FoundInstantiation = *I;
Instantiation = Method;
diff --git a/test/CodeGen/attr-target-mv.c b/test/CodeGen/attr-target-mv.c
index 0085a154ced1..48e155835697 100644
--- a/test/CodeGen/attr-target-mv.c
+++ b/test/CodeGen/attr-target-mv.c
@@ -70,6 +70,22 @@ void bar4() {
// CHECK: ret void ()* @foo_decls.sse4.2
// CHECK: ret void ()* @foo_decls
+// CHECK: define void @bar4()
+// CHECK: call void @foo_multi.ifunc()
+
+// CHECK: define void ()* @foo_multi.resolver() comdat
+// CHECK: and i32 %{{.*}}, 4352
+// CHECK: icmp eq i32 %{{.*}}, 4352
+// CHECK: ret void ()* @foo_multi.fma4_sse4.2
+// CHECK: icmp eq i32 %{{.*}}, 12
+// CHECK: and i32 %{{.*}}, 4352
+// CHECK: icmp eq i32 %{{.*}}, 4352
+// CHECK: ret void ()* @foo_multi.arch_ivybridge_fma4_sse4.2
+// CHECK: and i32 %{{.*}}, 768
+// CHECK: icmp eq i32 %{{.*}}, 768
+// CHECK: ret void ()* @foo_multi.avx_sse4.2
+// CHECK: ret void ()* @foo_multi
+
// CHECK: declare i32 @foo.arch_sandybridge()
// CHECK: define available_externally i32 @foo_inline.sse4.2()
@@ -88,4 +104,3 @@ void bar4() {
// CHECK: define available_externally void @foo_multi.avx_sse4.2()
// CHECK: define available_externally void @foo_multi.fma4_sse4.2()
// CHECK: define available_externally void @foo_multi.arch_ivybridge_fma4_sse4.2()
-
diff --git a/test/CodeGen/builtin-cpu-supports.c b/test/CodeGen/builtin-cpu-supports.c
index b70f4aca9d43..4964b98e6f52 100644
--- a/test/CodeGen/builtin-cpu-supports.c
+++ b/test/CodeGen/builtin-cpu-supports.c
@@ -14,7 +14,7 @@ int main() {
// CHECK: [[LOAD:%[^ ]+]] = load i32, i32* getelementptr inbounds ({ i32, i32, i32, [1 x i32] }, { i32, i32, i32, [1 x i32] }* @__cpu_model, i32 0, i32 3, i32 0)
// CHECK: [[AND:%[^ ]+]] = and i32 [[LOAD]], 256
- // CHECK: = icmp ne i32 [[AND]], 0
+ // CHECK: = icmp eq i32 [[AND]], 256
return 0;
}
diff --git a/test/Driver/cl-options.c b/test/Driver/cl-options.c
index 9aa6ced34994..59f565e6f2ec 100644
--- a/test/Driver/cl-options.c
+++ b/test/Driver/cl-options.c
@@ -566,6 +566,7 @@
// RUN: %clang_cl \
// RUN: --driver-mode=cl \
// RUN: -fblocks \
+// RUN: -fcrash-diagnostics-dir=/foo \
// RUN: -fno-blocks \
// RUN: -fbuiltin \
// RUN: -fno-builtin \
diff --git a/test/Driver/cl-pch.cpp b/test/Driver/cl-pch.cpp
index 8521d3576a7b..0103db93e1a1 100644
--- a/test/Driver/cl-pch.cpp
+++ b/test/Driver/cl-pch.cpp
@@ -345,3 +345,24 @@
// CHECK-NoSourceTP: pchfile.pch
// CHECK-NoSourceTP: -x
// CHECK-NoSourceTP: "c++"
+
+// If only preprocessing, PCH options are ignored.
+// RUN: %clang_cl /P /Ycpchfile.h /FIpchfile.h /c -### -- %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK-YC-P %s
+// CHECK-YC-P-NOT: -emit-pch
+// CHECK-YC-P-NOT: -include-pch
+
+// RUN: %clang_cl /E /Ycpchfile.h /FIpchfile.h /c -### -- %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK-YC-E %s
+// CHECK-YC-E-NOT: -emit-pch
+// CHECK-YC-E-NOT: -include-pch
+
+// RUN: %clang_cl /P /Ycpchfile.h /FIpchfile.h /c -### -- %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK-YU-P %s
+// CHECK-YU-P-NOT: -emit-pch
+// CHECK-YU-P-NOT: -include-pch
+
+// RUN: %clang_cl /E /Ycpchfile.h /FIpchfile.h /c -### -- %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK-YU-E %s
+// CHECK-YU-E-NOT: -emit-pch
+// CHECK-YU-E-NOT: -include-pch
diff --git a/test/Driver/linux-ld.c b/test/Driver/linux-ld.c
index 787013931a48..d4823a8d9f01 100644
--- a/test/Driver/linux-ld.c
+++ b/test/Driver/linux-ld.c
@@ -1648,6 +1648,14 @@
// CHECK-ARMV7EB: "--be8"
// CHECK-ARMV7EB: "-m" "armelfb_linux_eabi"
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=aarch64_be-unknown-linux \
+// RUN: --gcc-toolchain="" \
+// RUN: --sysroot=%S/Inputs/basic_linux_tree \
+// RUN: | FileCheck --check-prefix=CHECK-AARCH64BE %s
+// CHECK-AARCH64BE: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
+// CHECK-AARCH64BE: "-m" "aarch64linuxb"
+
// Check dynamic-linker for musl-libc
// RUN: %clang %s -### -o %t.o 2>&1 \
// RUN: --target=i386-pc-linux-musl \
diff --git a/test/PCH/Inputs/pch-through-use3c.cpp b/test/PCH/Inputs/pch-through-use3c.cpp
new file mode 100644
index 000000000000..6102c514fba3
--- /dev/null
+++ b/test/PCH/Inputs/pch-through-use3c.cpp
@@ -0,0 +1,2 @@
+int a = A;
+// expected-no-diagnostics
diff --git a/test/PCH/Inputs/pch-through3c.h b/test/PCH/Inputs/pch-through3c.h
new file mode 100644
index 000000000000..ab2a05dbbf84
--- /dev/null
+++ b/test/PCH/Inputs/pch-through3c.h
@@ -0,0 +1 @@
+#define A 1
diff --git a/test/PCH/pch-through3c.cpp b/test/PCH/pch-through3c.cpp
new file mode 100644
index 000000000000..97b98c405987
--- /dev/null
+++ b/test/PCH/pch-through3c.cpp
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -I %S -emit-pch \
+// RUN: -include Inputs/pch-through3c.h \
+// RUN: -pch-through-header=Inputs/pch-through3c.h -o %t.3c %s
+
+// RUN: %clang_cc1 -verify -I %S -include-pch %t.3c \
+// RUN: -include Inputs/pch-through3c.h \
+// RUN: -pch-through-header=Inputs/pch-through3c.h \
+// RUN: %S/Inputs/pch-through-use3c.cpp 2>&1
diff --git a/test/SemaCXX/cxx1y-deduced-return-type.cpp b/test/SemaCXX/cxx1y-deduced-return-type.cpp
index 13ff751acae4..5daba67bc56a 100644
--- a/test/SemaCXX/cxx1y-deduced-return-type.cpp
+++ b/test/SemaCXX/cxx1y-deduced-return-type.cpp
@@ -552,3 +552,73 @@ namespace PR24989 {
void forinit_decltypeauto() {
for (decltype(auto) forinit_decltypeauto_inner();;) {} // expected-warning {{interpreted as a function}} expected-note {{replace}}
}
+
+namespace PR33222 {
+ auto f1();
+ auto f2();
+
+ template<typename T> decltype(auto) g0(T x) { return x.n; }
+ template<typename T> decltype(auto) g1(T);
+ template<typename T> decltype(auto) g2(T);
+
+ struct X {
+ static auto f1();
+ static auto f2();
+
+ template<typename T> static decltype(auto) g0(T x) { return x.n; } // FIXME (PR38883): expected-error {{private}}
+ template<typename T> static decltype(auto) g1(T);
+ template<typename T> static decltype(auto) g2(T);
+ };
+
+ template<typename U> class A {
+ friend auto f1();
+ friend auto f2();
+
+ // FIXME (PR38883): This friend declaration doesn't actually work, because
+ // we fail to look up the named function properly during instantiation.
+ friend decltype(auto) g0<>(A);
+ template<typename T> friend decltype(auto) g1(T);
+ template<typename T> friend decltype(auto) g2(T);
+
+ friend auto X::f1();
+ friend auto X::f2();
+
+ // FIXME (PR38882): 'A' names the class template not the injected-class-name here!
+ friend decltype(auto) X::g0<>(A<U>);
+ // FIXME (PR38882): ::T hides the template parameter if both are named T here!
+ template<typename T_> friend decltype(auto) X::g1(T_);
+ template<typename T_> friend decltype(auto) X::g2(T_);
+
+ int n; // FIXME: expected-note {{here}}
+ };
+
+ auto f1() { return A<int>().n; }
+ template<typename T> decltype(auto) g1(T x) { return A<int>().n; }
+
+ auto X::f1() { return A<int>().n; }
+ template<typename T> decltype(auto) X::g1(T x) { return A<int>().n; }
+
+ A<int> ai;
+ int k1 = g0(ai);
+ int k2 = X::g0(ai); // FIXME: expected-note {{in instantiation of}}
+
+ int k3 = g1(ai);
+ int k4 = X::g1(ai);
+
+ auto f2() { return A<int>().n; }
+ template<typename T> decltype(auto) g2(T x) { return A<int>().n; }
+
+ auto X::f2() { return A<int>().n; }
+ template<typename T> decltype(auto) X::g2(T x) { return A<int>().n; }
+
+ int k5 = g2(ai);
+ int k6 = X::g2(ai);
+
+ template<typename> struct B {
+ auto *q() { return (float*)0; } // expected-note 2{{previous}}
+ };
+ template<> auto *B<char[1]>::q() { return (int*)0; }
+ template<> auto B<char[2]>::q() { return (int*)0; } // expected-error {{return type}}
+ // FIXME: suppress this follow-on error: expected-error@-1 {{cannot initialize}}
+ template<> int B<char[3]>::q() { return 0; } // expected-error {{return type}}
+}
diff --git a/test/SemaCXX/friend.cpp b/test/SemaCXX/friend.cpp
index 1f64ba609b16..61e96922f6d5 100644
--- a/test/SemaCXX/friend.cpp
+++ b/test/SemaCXX/friend.cpp
@@ -388,3 +388,26 @@ namespace default_arg {
friend void f(void *p = 0) {} // expected-error {{must be the only}}
};
}
+
+namespace PR33222 {
+ int f();
+ template<typename T> struct X {
+ friend T f();
+ };
+ X<int> xi;
+
+ int g(); // expected-note {{previous}}
+ template<typename T> struct Y {
+ friend T g(); // expected-error {{return type}}
+ };
+ Y<float> yf; // expected-note {{instantiation}}
+
+ int h();
+ template<typename T> struct Z {
+ // FIXME: The note here should point at the non-friend declaration, not the
+ // instantiation in Z<int>.
+ friend T h(); // expected-error {{return type}} expected-note {{previous}}
+ };
+ Z<int> zi;
+ Z<float> zf; // expected-note {{instantiation}}
+}