summaryrefslogtreecommitdiffstats
path: root/clang/lib/Sema/SemaExpr.cpp
diff options
context:
space:
mode:
authorReid Kleckner <rnk@google.com>2019-06-10 22:53:12 +0000
committerReid Kleckner <rnk@google.com>2019-06-10 22:53:12 +0000
commite78333a0105dc3e653d47be0aceeea9c7972ab23 (patch)
tree03c5b68cfea5a6d27cc191eef329853a5c76a397 /clang/lib/Sema/SemaExpr.cpp
parentee5881a88cbe148bb64d14b8a5b31a314ee22343 (diff)
downloadbcm5719-llvm-e78333a0105dc3e653d47be0aceeea9c7972ab23.tar.gz
bcm5719-llvm-e78333a0105dc3e653d47be0aceeea9c7972ab23.zip
Require stdcall etc parameters to be complete on ODR use
Functions using stdcall, fastcall, or vectorcall with C linkage mangle in the size of the parameter pack. Calculating the size of the pack requires the parameter types to complete, which may require template instantiation. Previously, we would crash during IRgen when requesting the size of incomplete or uninstantiated types, as in this reduced example: struct Foo; void __fastcall bar(struct Foo o); void (__fastcall *fp)(struct Foo) = &bar; Reported in Chromium here: https://crbug.com/971245 Differential Revision: https://reviews.llvm.org/D62975 llvm-svn: 363000
Diffstat (limited to 'clang/lib/Sema/SemaExpr.cpp')
-rw-r--r--clang/lib/Sema/SemaExpr.cpp81
1 files changed, 81 insertions, 0 deletions
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 7eb5bcbbbb0..2b714a36e2a 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -14793,6 +14793,81 @@ static bool isPotentiallyConstantEvaluatedContext(Sema &SemaRef) {
llvm_unreachable("Invalid context");
}
+/// Return true if this function has a calling convention that requires mangling
+/// in the size of the parameter pack.
+static bool funcHasParameterSizeMangling(Sema &S, FunctionDecl *FD) {
+ // These manglings don't do anything on non-Windows or non-x86 platforms, so
+ // we don't need parameter type sizes.
+ const llvm::Triple &TT = S.Context.getTargetInfo().getTriple();
+ if (!TT.isOSWindows() || (TT.getArch() != llvm::Triple::x86 &&
+ TT.getArch() != llvm::Triple::x86_64))
+ return false;
+
+ // If this is C++ and this isn't an extern "C" function, parameters do not
+ // need to be complete. In this case, C++ mangling will apply, which doesn't
+ // use the size of the parameters.
+ if (S.getLangOpts().CPlusPlus && !FD->isExternC())
+ return false;
+
+ // Stdcall, fastcall, and vectorcall need this special treatment.
+ CallingConv CC = FD->getType()->castAs<FunctionType>()->getCallConv();
+ switch (CC) {
+ case CC_X86StdCall:
+ case CC_X86FastCall:
+ case CC_X86VectorCall:
+ return true;
+ default:
+ break;
+ }
+ return false;
+}
+
+/// Require that all of the parameter types of function be complete. Normally,
+/// parameter types are only required to be complete when a function is called
+/// or defined, but to mangle functions with certain calling conventions, the
+/// mangler needs to know the size of the parameter list. In this situation,
+/// MSVC doesn't emit an error or instantiate templates. Instead, MSVC mangles
+/// the function as _foo@0, i.e. zero bytes of parameters, which will usually
+/// result in a linker error. Clang doesn't implement this behavior, and instead
+/// attempts to error at compile time.
+static void CheckCompleteParameterTypesForMangler(Sema &S, FunctionDecl *FD,
+ SourceLocation Loc) {
+ class ParamIncompleteTypeDiagnoser : public Sema::TypeDiagnoser {
+ FunctionDecl *FD;
+ ParmVarDecl *Param;
+
+ public:
+ ParamIncompleteTypeDiagnoser(FunctionDecl *FD, ParmVarDecl *Param)
+ : FD(FD), Param(Param) {}
+
+ void diagnose(Sema &S, SourceLocation Loc, QualType T) override {
+ CallingConv CC = FD->getType()->castAs<FunctionType>()->getCallConv();
+ StringRef CCName;
+ switch (CC) {
+ case CC_X86StdCall:
+ CCName = "stdcall";
+ break;
+ case CC_X86FastCall:
+ CCName = "fastcall";
+ break;
+ case CC_X86VectorCall:
+ CCName = "vectorcall";
+ break;
+ default:
+ llvm_unreachable("CC does not need mangling");
+ }
+
+ S.Diag(Loc, diag::err_cconv_incomplete_param_type)
+ << Param->getDeclName() << FD->getDeclName() << CCName;
+ }
+ };
+
+ for (ParmVarDecl *Param : FD->parameters()) {
+ ParamIncompleteTypeDiagnoser Diagnoser(FD, Param);
+ S.RequireCompleteType(Loc, Param->getType(), Diagnoser);
+ }
+}
+
namespace {
enum class OdrUseContext {
/// Declarations in this context are not odr-used.
@@ -15038,6 +15113,12 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func,
UndefinedButUsed.insert(std::make_pair(Func->getCanonicalDecl(), Loc));
}
+ // Some x86 Windows calling conventions mangle the size of the parameter
+ // pack into the name. Computing the size of the parameters requires the
+ // parameter types to be complete. Check that now.
+ if (funcHasParameterSizeMangling(*this, Func))
+ CheckCompleteParameterTypesForMangler(*this, Func, Loc);
+
Func->markUsed(Context);
if (LangOpts.OpenMP && LangOpts.OpenMPIsDevice)
OpenPOWER on IntegriCloud