diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp --- a/clang/lib/CodeGen/CGStmt.cpp +++ b/clang/lib/CodeGen/CGStmt.cpp @@ -2467,7 +2467,8 @@ // that is usually cheaper, but LLVM IR should really get an anyext someday. if (Info.hasTiedOperand()) { unsigned Output = Info.getTiedOperand(); - QualType OutputType = S.getOutputExpr(Output)->getType(); + const Expr *OutputExpr = S.getOutputExpr(Output); + QualType OutputType = OutputExpr->getType(); QualType InputTy = InputExpr->getType(); if (getContext().getTypeSize(OutputType) > @@ -2480,10 +2481,14 @@ Arg = Builder.CreateZExt(Arg, OutputTy); else if (isa(OutputTy)) Arg = Builder.CreateZExt(Arg, IntPtrTy); - else { - assert(OutputTy->isFloatingPointTy() && "Unexpected output type"); + else if (OutputTy->isFloatingPointTy()) Arg = Builder.CreateFPExt(Arg, OutputTy); - } + else + // FIXME: GCC and ICC can handle structure type that have more than 1 + // element. We may need to match the same behavior. + CGM.getDiags().Report(S.getAsmLoc(), diag::err_asm_invalid_type) + << OutputExpr->getType() << 1 /*Output*/ + << OutputExpr->getSourceRange(); } // Deal with the tied operands' constraint code in adjustInlineAsmType. ReplaceConstraint = OutputConstraints[Output]; diff --git a/clang/lib/Sema/SemaStmtAsm.cpp b/clang/lib/Sema/SemaStmtAsm.cpp --- a/clang/lib/Sema/SemaStmtAsm.cpp +++ b/clang/lib/Sema/SemaStmtAsm.cpp @@ -666,7 +666,8 @@ // output was a register, just extend the shorter one to the size of the // larger one. if (!SmallerValueMentioned && InputDomain != AD_Other && - OutputConstraintInfos[TiedTo].allowsRegister()) + OutputConstraintInfos[TiedTo].allowsRegister() && + (OutputDomain != AD_Other || OutSize <= InSize)) continue; // Either both of the operands were mentioned or the smaller one was diff --git a/clang/test/Sema/asm.c b/clang/test/Sema/asm.c --- a/clang/test/Sema/asm.c +++ b/clang/test/Sema/asm.c @@ -313,3 +313,23 @@ asm ("jne %l0":::); asm goto ("jne %l0"::::lab); } + +// FIXME: GCC and ICC support this case. We may need to follow them. +typedef struct test19_foo { + int a; + char b; +} test19_foo; + +typedef struct test19_bar { + int a; + int b; + int c; +} test19_bar; + +void test19() +{ + test19_foo a; + test19_bar b; + asm ("" : "=rm" (a): "0" (1)); // expected-error {{unsupported inline asm: input with type 'int' matching output with type 'test19_foo' (aka 'struct test19_foo')}} + asm ("" : "=rm" (b): "0" (1)); // expected-error {{unsupported inline asm: input with type 'int' matching output with type 'test19_bar' (aka 'struct test19_bar')}} +}